【问题标题】:C++ Need help sorting a 2D string arrayC++ 需要帮助对二维字符串数组进行排序
【发布时间】:2021-06-02 02:38:48
【问题描述】:

我对排序字符串 Table[X][Y] 有点卡住。正如标记的那样,我使用 C++ 并且必须使用标准库并使其适用于所有 C++(不仅仅是 C++ 11)。

Table 的大小是固定的(我让 X 读取文件有多少行,而 Y 是固定的,因为每一行都有不同的“属性”)。

当我创建表时,它的每个部分都以Table[X][Y] = stringX.data(); 的形式从先前从文件中读取并存储在字符串中的内容中获取。我在第一列中有数字(我将用作排序标准的那个),在其他列中有姓名、地​​址等。

创建Table的部分是:

Table[i][0] = string1.data();
Table[i][1] = string2.data();
Table[i][2] = string3.data();
Table[i][3] = string4.data();
Table[i][4] = string5.data();

其中“i”是while(fgets) 的当前“迭代”,它一次从文件中读取一行,执行一些操作并将读取的行的每个部分的“最终值”存储在这些字符串中。

我必须使用第一列作为标准以降序对该表进行排序。

让我们想象一下表格是这样的:Table[4][3]

20 | Jhon  | 14th July 
2  | Mary  | 9th June
44 | Mark  | 10th December
1  | Chris | 4th Feb

我需要这样的输出:

44 | Mark  | 10th December
20 | Jhon  | 14th July 
2  | Mary  | 9th June
1  | Chris | 4th Feb

我一直在阅读几个问题和页面,他们对 int/chars 数组进行排序或将数组转换为向量,然后使用它们。我试图在不转换任何内容的情况下对我拥有的字符串表进行排序(如果可能的话不知道)。

我不知道我是否设法解释了我已经足够清楚的问题和情况。我没有把我拥有的所有代码都放好,因为除了字符串表的声明和随后作为 string.data 放置在表中的字符串之外,其余代码与表和排序过程无关。代码打开文件,逐行读取,从一些分隔符和特殊字符中过滤我需要的信息,并将每个“排名标准”​​放到一个字符串中,然后在评估每个标准后分配一个“排名”并给出一个总分(然后存储在“string1”中)。 完成所有这些后,我创建字符串Table[x][y],并将过滤和处理的信息一次放置在该表中的一行中(因为我在从文件中读取每一行时都设置了这个)。

唯一剩下的就是将表格从得分最高的到最后的排序,然后创建一个包含前 10 名的文件。

我提前感谢并感谢您花时间阅读本文以及您可以提供的任何提示、信息、代码或来源。

【问题讨论】:

  • 表格的大小是固定的(我让 X 读取文件有多少行,而 Y 是固定的,因为每一行都有不同的“属性”)。——对我来说,这听起来不像是“固定”大小。大小取决于行数。如果是这种情况,并且XY 实际上是运行时变量,那么std::string Table[X][Y]; 不是有效的C++。不要描述,而是发布minimal reproducible example。如果目标是对第一列进行排序,那么数据的来源并不重要。
  • 为了清楚起见,您遗漏了与您的代码有关的最重要的信息——Table 实际上是如何声明的?同样,如果它是 int X; int Y; X = somevalue; Y = somevalue;...std::string Table[X][Y]; 之类的东西,那么这不是标准 C++,因此你制作这个 C++ 的目标不会实现。
  • 我从这段代码中得到 X:while(fgets(inputArray, sizeof(inputArray), fp) != NULL) { lineCount++;有了这个,我读取了所有文件并获取了文件的所有行,然后我使用变量“lineCount”作为表中的 X。 Y 是每个人拥有的“属性”的数量。在我的情况下是 6(姓名,姓氏,出生,性别,地址),最后一个是我给他们每个人的值,并且表的声明就像我所说的 => string Table[lineCount][6]跨度>
  • 如前所述,这不是有效的 C++。可变长度数组从未成为标准 C++ 的一部分。 C++ 中的数组的大小必须由编译时常量而不是运行时变量来表示。如果列数是固定的,那么 std::vector<std::array<std::string, 6>> Table(lineCount); 将是有效的 C++。 C++ 中的可变长度数组是std::vector。您现在使用的是某些编译器提供的编译器扩展,但如果您好奇,您的代码将无法使用 Visual Studio 或其他不接受非标准语法的编译器进行编译。
  • 不要调用 data() 来存储字符串 char 数据。只存储字符串本身。

标签: c++ arrays sorting


【解决方案1】:

首先,如 cmets 中所述,可变长度数组是在 C++ 中使用std::vector 完成的。您当前使用的语法

std::string Table[X][Y]

XY 是运行时变量,不是合法的 C++。鉴于您的示例,标准 C++ 声明将是这样的:

std::vector<std::array<std::string, 3>> Table;

所以让我们假设这是您将要使用的。


下一步是根据第一列对数据进行排序。这可以通过使用std::sort 算法函数以及表明您使用第一列作为排序标准的适当谓词来实现。

下面是一个简短的示例,使用您的数据说明这一切是如何完成的:

#include <vector>
#include <array>
#include <iostream>
#include <algorithm>
#include <string>

int main()
{
    std::vector<std::array<std::string, 3>> Table;

    // Set up the test data  
    Table.push_back({"20", "Jhon", "14th July"});
    Table.push_back({"2", "Mary", "9th June"});
    Table.push_back({"44", "Mark", "10th December"});
    Table.push_back({"1", "Chris", "4th Feb"});

    std::cout << "Before sort:\n\n";
    for (auto& s : Table)
        std::cout << s[0] << " | " << s[1] << " | " << s[2] << "\n";
        
    std::cout << "\n\nAfter sort:\n\n";
    
    // Sort the data using the first column of each `std::array` as the criteria
    std::sort(Table.begin(), Table.end(), [&](auto& a1, auto& a2) 
              { return std::stoi(a1[0]) > std::stoi(a2[0]); });

    // Output the results: 
    for (auto& s : Table)
        std::cout << s[0] << " | " << s[1] << " | " << s[2] << "\n";
}

这是最终输出:

Before sort:

20 | Jhon | 14th July
2 | Mary | 9th June
44 | Mark | 10th December
1 | Chris | 4th Feb


After sort:

44 | Mark | 10th December
20 | Jhon | 14th July
2 | Mary | 9th June
1 | Chris | 4th Feb

输出需要一些格式化,但这并不重要。

请记住,数据来自哪里并不重要,无论是来自文件还是硬编码,如上例所示。无论您填充Table,这都取决于您。目标是向您展示填充后如何对数据进行排序。


我们做的第一件事是创建表格并用测试数据填充它。请注意,向量有一个push_back 函数可以向向量中添加条目。

然后对std::sort 的调用有一个谓词函数(lambda),其中谓词有两个项目,在这种情况下它将是两个std::array 的引用。那么目标是如果第一个std::array(在本例中为a1)应该放在第二个std::arraya2)之前,则返回。

注意我们只关心第一列,所以我们只需要考虑每个数组的array[0],然后比较它们。

还要注意,由于 array[0] 是 std::string,我们根本无法按字典顺序比较它——我们需要将字符串转换为 int 并比较 int 的值。这就是 std::stoi 调用转换为整数的原因。

关于排序谓词的最后一件事是我们想要进行降序排序。因此,要使用的比较运算符是&gt;,而不是“传统的”&lt;(它会以升序方式排序)。

希望这能解释代码在做什么。


编辑:

由于您试图让这段代码在 C++98 中工作,最简单的方法是

  1. 更改为 std::vector&lt;std::vector&lt;std::string&gt;&gt; 而不是 std::vector&lt;std::array&lt;std::string, 3&gt;&gt;

  2. 不使用 C++11 提供的大括号初始化

  3. 使用比较函数而不是 lambda。

鉴于此,这里是 C++98 的代码:

#include <vector>
#include <iostream>
#include <algorithm>
#include <string>

bool SortFirstColumn(const std::vector<std::string>& a1,
                     const std::vector<std::string>& a2)
{
   return atoi(a1[0].c_str()) > atoi(a2[0].c_str());
}
 
int main()
{
    std::vector<std::vector<std::string>> Table;

    // Set up the test data  
    std::vector<std::string> vect(3);
    vect[0] = "20"; 
    vect[1] = "Jhon"; 
    vect[2] = "14th July"; 
    Table.push_back(vect);
    vect[0] = "2"; 
    vect[1] = "Mary"; 
    vect[2] = "9th June"; 
    Table.push_back(vect);
    vect[0] = "44"; 
    vect[1] = "Mark"; 
    vect[2] = "10th December"; 
    Table.push_back(vect);
    vect[0] = "1"; 
    vect[1] = "Chris"; 
    vect[2] = "10th December"; 
    Table.push_back(vect);

    std::cout << "Before sort:\n\n";
    for (size_t i = 0; i < Table.size(); ++i)
        std::cout << Table[i][0] << " | " << Table[i][1] << " | " << Table[i][2] << "\n";
        
    std::cout << "\n\nAfter sort:\n\n";
    
    // Sort the data using the first column of each `std::vector<std::string>` as the criteria
    std::sort(Table.begin(), Table.end(), SortFirstColumn);

    // Output the results: 
    for (size_t i = 0; i < Table.size(); ++i)
        std::cout << Table[i][0] << " | " << Table[i][1] << " | " << Table[i][2] << "\n";
}

【讨论】:

  • 当我在带有选项 C++98 和警告 -Wpedantic 的在线编译器“cpp.sh”中尝试此代码时,我收到以下错误:“#error 此文件需要编译器和库支持ISO C++ 2011 标准。此支持目前是实验性的,必须使用 -std=c++11 或 -std=gnu++11 编译器选项启用”(例如,使用回推产生的不同错误除外) .使用 C++11 时失败,因为 lambda 参数仅适用于 C++14。使用 C++14 时,它运行没有问题,但由于我必须使用 C++98(使其可在任何编译器中使用),所以我遇到了这个问题。
  • 有没有办法让这种 C++98 成为可能?我知道这段代码在做什么,这对我理解排序非常有帮助,但由于我不能在 C98 中使用 push back,我对如何解决这个问题有点迷茫。尽管如此,我真的很感激时间和答案,它将帮助我理解更多的向量和排序。
  • 当返回时,第 9 行的参数 '1' 到 'int atoi(const char*)' 的参数“无法将 'const std::basic_string' 转换为 'const char*' atoi 位于。现在我正在查看代码并试图了解该行正在尝试做什么以及如何解决它。我知道 atoi 将字符串转换为 int 并且 c_str 给出了字符串的 char 指针,但我需要了解整行。
  • 右括号放错了。现在代码应该可以编译了。
  • 很好,刚刚测试过,工作正常。现在我将把向量初始化从这个定义的结构更改为一个循环,我将每个组件从一个字符串中放置。该字符串由从文件中逐行读取的信息填充并标记化,因为它们具有分隔每个字段的“&”。列是 6,所以它应该是“vect(6)”。我想我可以设法适应它而没有进一步的问题......但如果我碰巧发现问题,我可能会再打扰你一次(如果你没问题的话)。感谢您的帮助。
猜你喜欢
  • 2015-06-28
  • 1970-01-01
  • 2011-02-17
  • 1970-01-01
  • 2021-08-16
  • 2014-08-10
  • 2014-06-29
  • 2021-11-08
相关资源
最近更新 更多