繁体   English   中英

如何对按第二种类型(int)排序的二维数组进行排序?

[英]How can I sort a 2D array of pairs sorted by its second type (int)?

我有一个二维数组,它计算一个词出现的次数。 我想对它进行排序,以便出现最多的词排在最前面。

示例二维数组(排序前):

hello  3
jack   5
the    2
fish  10

排序后:

fish  10
jack   5
hello  3
the    2

如果你有你的std::array<std::pair<std::string,int>,4>并且想要对int值进行降序排序(例如对的.second成员),你可以简单地写一个 Lamba函数接受两个std::pair<std::string,int>& a (和b )对,然后如果ab之前排序, .second对的.second成员进行降序排序,则返回true

例如,您可以编写一个名为how to tell std::sort如何对数组进行排序的 lambda。 可以写成:

  /* lambda to sort std::pair<std::string,int> by .second descending */
  auto how = [](std::pair<std::string,int>& a,
                std::pair<std::string,int>& b) {
    return a.second > b.second;
  };

通过在a.second大于b.second时返回true ,您可以根据 std::pair 的.second成员定义降序排序。

一个简短的例子是:

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

int main (void) {
  
  /* std::pair is an aggregate and its initializer must be {..} enclosed
   * std::array { std::pair { pairs {"s", n}, {"t", m}, ... } }
   */
  std::array<std::pair<std::string,int>,4> arr {{ {"hello", 3},
                                                  {"jack", 5},
                                                  {"the", 2},
                                                  {"fish", 10} }};
  
  /* lambda to sort std::pair<std::string,int> by .second descending */
  auto how = [](std::pair<std::string,int>& a,
                std::pair<std::string,int>& b) {
    return a.second > b.second;
  };
  
  /* sort arr */
  std::sort (arr.begin(), arr.end(), how);
  
  /* output result */
  for (const auto& p : arr)
    std::cout << p.first << " " << p.second << '\n';
}

示例使用/输出

$ ./bin/sort_array_pairs
fish 10
jack 5
hello 3
the 2

使用operator()的类/结构模板重载

是另一种选择,它允许您提供一个类实现,该实现与将上面的 lambda 用于std::sort执行相同的操作。 您可以使用带有std::sortstruct类型来编写一个简短的结构,而不是 Lamba,它重载bool operator()并返回相同的比较。

例如:

  struct {
    bool operator() (std::pair<std::string,int>& a,
                     std::pair<std::string,int>& b) const {
      return a.second > b.second;
    }
  } sort_desc_2nd;

您对std::sort调用将是:

  std::sort (arr.begin(), arr.end(), sort_desc_2nd);

(同样的结果)

我不确定一个是否比另一个更受欢迎,只知道您可以选择如何定义自定义排序并选择最适合您情况的方法。 两者的示例都在std::sortlambda 中显示为注释中提供的@SomeProgrammerDude。

整个故事似乎是关于计算单词,然后将 regadrs 排名到单词的频率。

有一种或多或少的标准方法来计算容器中的东西,然后获取并显示它的等级。

对于计数部分,我们可以使用关联容器,如std::mapstd::unordered_map 在这里,我们将一个“键”(在这种情况下是单词)与一个计数和一个值(在这种情况下是特定单词的计数)相关联。

幸运的是,基本上选择这种方法的原因是地图有一个非常好的索引operator[] 这将查找给定的键,如果找到,则返回对该值的引用。 如果未找到,则它将使用该键创建一个新条目并返回对新条目的引用。 因此,在这两种情况下,我们都将获得对用于计数的值的引用。 然后我们可以简单地写:

std::unordered_map<char,int> counter{};
counter[word]++;

这看起来非常直观。

完成此操作后,您已经有了频率表。 通过使用std::map或未排序的键(单词)排序,但使用std::unordered_map可以更快地访问。

在您的情况下,您只对排序计数感兴趣,建议使用std::unordered_map ,因为无需按键对std::map的数据进行排序,以后也不使用此排序。

然后,您想根据频率/计数进行排序。 不幸的是,这在地图上是不可能的。 因为映射- 容器系列的主要属性是它们对的引用,而不是值或计数。

因此,我们需要使用第二个容器,例如std::vector等,然后我们可以使用std::sort对任何给定的谓词进行std::sort ,或者,我们可以将值复制到容器中,例如std::multiset隐式排序其元素的std::multiset 因为这只是一个衬里,所以这是推荐的解决方案。

此外,因为要为 std 容器编写所有这些长名称,所以我们using关键字创建别名。

在我们获得单词的排名后,即按计数排序的单词列表,我们可以使用迭代器和循环来访问数据并输出它们。

补充说明。 为了定义一个词是什么,我们使用std::regex 这非常强大,您可以根据自己的需要进行调整。 为了获取单词,我们使用std::sregex_token:iterator字符串。

这将为我们提供一个超紧凑且功能强大的代码来完成整个字数统计任务。

请参阅以下内容:

#include <iostream>
#include <string>
#include <fstream>
#include <utility>
#include <set>
#include <unordered_map>
#include <type_traits>
#include <iomanip>
#include <regex>

// ------------------------------------------------------------
// Create aliases. Save typing work and make code more readable
using Pair = std::pair<std::string, unsigned int>;

// Standard approach for counter
using Counter = std::unordered_map<Pair::first_type, Pair::second_type>;

// Sorted values will be stored in a multiset
struct Comp { bool operator ()(const Pair& p1, const Pair& p2) const { return (p1.second == p2.second) ? p1.first<p2.first : p1.second>p2.second; } };
using Rank = std::multiset<Pair, Comp>;
using WordIter = std::sregex_token_iterator;

// Define this or any other pattern that constitutes an English word
const std::regex re{ "([a-zA-Z]+)" };

// ------------------------------------------------------------
std::string loremIpsum{ R"(Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam 
erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum 
dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.)" };

// --------------------------------------------------------------------------------------
// Compact function to calculate the frequency of words and then get their rank
Rank getRank(std::string text) {

    // Definition of our counter
    Counter counter{};

    // Iterate over all words in text and count the frequency of the words
    for (auto word{ WordIter(text.begin(),text.end(), re) }; word != WordIter(); ++word)
        counter[*word]++;

    // Return sorted pairs
    return { counter.begin(), counter.end() };
}

// --------------------------------------------------------------------------------------
// Test, driver code
int main() {

    // Calculate rank and show result
    for (const auto& [word, count] : getRank(loremIpsum))
        std::cout << std::setw(20) << word << " --> " << count << '\n';
}

请注意: getRank只包含 4 条语句和主要 2 条语句。其他一切都由智能容器处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM