将字符串排序为双精度

Sort String as double

我正在尝试按升序将我的文件内容排序为双精度

我的输入文件包含例如这些行:

105 350 4.41386e-06 4.41386e-06 
115 300 4.58965e-06 4.58965e-06 
15  150 1.6457e-06  1.6457e-06  
255 550 5.33661e-05 5.33661e-05 
25  150 3.21907e-06 3.21907e-06 
35  550 2.57952e-05 2.57952e-05 
45  150 1.78332e-06 1.78332e-06 

我希望我的输出文件具有如下内容:

15  150 1.6457e-06  1.6457e-06  
25  150 3.21907e-06 3.21907e-06 
35  550 2.57952e-05 2.57952e-05 
45  150 1.78332e-06 1.78332e-06 
105 350 4.41386e-06 4.41386e-06 
115 300 4.58965e-06 4.58965e-06 
255 550 5.33661e-05 5.33661e-05

由于我只是 C++ 编码的初学者,如果尝试过这些行来完成该任务:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main()
{
    std::ifstream textfile( "Limit.txt" );
    std::string text_input;
    std::vector< std::string > sort_vec;
    std::ofstream outfile1;
    TString outfile_name1 = "Limits.txt";
    if ( textfile.is_open() )
    {
        outfile1.open( outfile_name1 );

        while ( std::getline( textfile,text_input ) )
        {  
            sort_vec.push_back(text_input);
        }

        textfile.close();
    }

    std::sort( std::begin( sort_vec ), std::end( sort_vec ), std::less<string>() );
    
    for ( const auto & e : sort_vec )
    {
        outfile1 << e << "\n";
    }

    outfile1.close();
}

但是我得不到我想要的结果。

能不能帮我解决一下。

正如评论中指出的,这里的问题是 std::less<std::string> 按字典顺序对字符串进行排序(即与它在字典中出现的顺序相同)。

这不是预期的行为,因为排序将逐个字符执行,而不是按值执行。

要实现正确的行为,您需要制作一个自定义比较器,它将提取 double 值以根据它执行排序。

例如(使用 lambda):

std::sort(sort_vec.begin(), sort_vec.end(), [](const std::string & lhs, const std::string & rhs){
    double ld, rd;
    std::stringstream{lhs} >> ld;
    std::stringstream{rhs} >> rd;

    return ld < rd;
});

它会成功 (live example here)

由于每行中的空格和不同长度的数据,将行作为字符串进行字典顺序排序可能会产生意想不到的结果或完全错误。

因此我建议将这些行分成 4 个部分,使用 >> 运算符使用普通 IO-extract-functionality 非常简单。

一行数据可以存储在一个结构中。这在某种程度上是直观的、可读的和可理解的。为了存储整个列表,我们可以使用这种结构的 std::vector

除了使用结构,我们还可以使用 Jarod42 提议的 std::tuplestd::tuple 具有比较运算符,允许稍后对一行进行超简单排序。

无论如何。让我们从一个结构开始,它有更多的可能性,如下所示。

  1. 定义结构
  2. 打开文件并检查是否可以打开
  3. 定义一个std::vector上述结构
  4. 创建结构的临时实例,以便能够将数据读入其中
  5. 在一个循环中,从文件中提取数据并存储在struct-elements
  6. 将每个刚刚读取的数据推回vector(我们称之为数据库)
  7. 使用 lambda 表达式排序以完全控制事物的排序方式
  8. 向用户显示结果

这可以用多种方式编码。查看下面的潜在示例:

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iomanip>

struct Data {
    int i1{};
    int i2{};
    double d1{};
    double d2{};
};

int main() {

    // Open the source textfile and check, if it could be opened
    std::ifstream textfile("Limit.txt");
    if (textfile) {

        // Here we will store all data
        std::vector<Data> database{};

        // Temporary storage for 1 line
        Data data{};

        // Read all lines and add data to the database
        while (textfile >> data.i1 >> data.i2 >> data.d1 >> data.d2)
            database.push_back(data);

        // Sort database and use a lambda to do it as wished
        std::sort(database.begin(), database.end(), [](const Data& d1, const Data& d2) {
            return d1.i1 == d2.i1 ? (d1.i2 == d2.i2 ? (d1.d1 == d2.d1 ? d1.d2 < d2.d1 : d1.d1 < d2.d1) : d1.i2 < d2.i2) : d1.i1 < d2.i1; });

        // Debug output
        for (const Data& d : database)
            std::cout << std::left << std::setw(4) << d.i1 << std::setw(4) << d.i2 << std::setw(12) << d.d1 << d.d2 << '\n';
    }
    else std::cerr << "\n*** Error! Could not open source file\n\n";
}

但这还不是全部。

如您所知,C++ 是一种面向对象的语言。我们可以将数据与函数一起存储在结构中,对这些数据进行操作(结构是 class)。

因此,我们可以添加输入和输出函数以及排序所需的小于运算符。

那么main函数就会简单很多

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iomanip>

struct Data {
    int i1{};
    int i2{};
    double d1{};
    double d2{};

    // Methods / operators
    // Input
    friend std::istream& operator >> (std::istream& is, Data& data) {
        return is >> data.i1 >> data.i2 >> data.d1 >> data.d2;
    }
    // Output
    friend std::ostream& operator << (std::ostream& os, const Data& d) {
        return os << std::left << std::setw(4) << d.i1 << std::setw(4)
            << d.i2 << std::setw(12) << d.d1 << d.d2;
    }
    // Comparison
    bool operator < (const Data& other) {
        return i1 == other.i1 ? (i2 == other.i2 ? (d1 == other.d1 ? d2 < other.d1 : d1 < other.d1) : i2 < other.i2) : i1 < other.i1;
    }

};

int main() {

    // Open the source textfile and check, if it could be opened
    std::ifstream textfile("Limit.txt");
    if (textfile) {

        // Here we will store all data
        std::vector<Data> database{};

        // Temporary storage for 1 line
        Data data{};

        // Read all lines and add data to the database
        while (textfile >> data)
            database.push_back(data);

        // Sort database
        std::sort(database.begin(), database.end());

        // Debug output
        for (const Data& d : database)
            std::cout << d << '\n';
    }
    else std::cerr << "\n*** Error! Could not open source file\n\n";
}

优点:简单易懂。良好的排序控制。 缺点:排序标准复杂

由于您想要基于 left-to-right 中的列进行分层排序,因此有多种方法可以使用 std::sort

一种方法是将元组组件的值读入 std::tuple and apply std::sort on a vector of these tuples. The tuple class will automatically do a lexicographical compare,来自 left-to-right。

std::tuple<int, int, double, double> 基本上模仿了一行数据。

#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <sstream>

std::string test = 
"105 350 4.41386e-06 4.41386e-06\n"
"115 300 4.58965e-06 4.58965e-06\n" 
"15  150 1.6457e-06  1.6457e-06\n"  
"255 550 5.33661e-05 5.33661e-05\n" 
"25  150 3.21907e-06 3.21907e-06\n" 
"35  550 2.57952e-05 2.57952e-05\n" 
"45  150 1.78332e-06 1.78332e-06\n"
"105 35  4.41386e-06 4.41386e-06\n" 
"115 300 4.58965e-06 4.58965e-09\n" 
"15  150 1.6457e-04  1.6457e-04\n"  
"255 550 5.33661e-05 5.33661e-02";


using DataLine = std::tuple<int, int, double, double>;
using VectorDataLine = std::vector<DataLine>;

int main()
{
    std::istringstream textfile(test);
    VectorDataLine sort_vec;
    DataLine data_line;
    while ( textfile >> std::get<0>(data_line) >> 
                        std::get<1>(data_line) >> 
                        std::get<2>(data_line) >> 
                        std::get<3>(data_line)) 
    {  
       sort_vec.push_back(data_line);
    }
    std::sort( std::begin( sort_vec ), std::end( sort_vec ));

    for ( const auto & e : sort_vec )
    {
        std::cout << std::get<0>(e) << ' ' <<
                     std::get<1>(e) << ' ' << 
                     std::get<2>(e) << ' ' << 
                     std::get<3>(e)  << "\n";
    }
}

输出:

15 150 1.6457e-06 1.6457e-06
15 150 0.00016457 0.00016457
25 150 3.21907e-06 3.21907e-06
35 550 2.57952e-05 2.57952e-05
45 150 1.78332e-06 1.78332e-06
105 35 4.41386e-06 4.41386e-06
105 350 4.41386e-06 4.41386e-06
115 300 4.58965e-06 4.58965e-09
115 300 4.58965e-06 4.58965e-06
255 550 5.33661e-05 5.33661e-05
255 550 5.33661e-05 0.0533661