【问题标题】:Removing duplicate elements of a vector of pairs based on individual elements inside the pair根据对中的单个元素删除对向量的重复元素
【发布时间】:2016-09-29 09:29:03
【问题描述】:

所以我需要在文件中找到一些最常用的词。

我有一个vector<pair<string, int> > wordList,它跟踪文件中的每个单词及其频率。这部分工作正常。

问题是,输出显示每个单词的多个版本。这是因为我的计算方式是:

  • 将所有单词加载到频率为 1 的向量中
  • 再过一遍,如果这个词出现两次,增加它的计数
  • 我需要帮助的部分是删除同一个单词的多个条目。

    for(int j = 0; j < wordList.size(); j++)
    {
    

这是我目前的方法。此功能汇总了所有单词。问题在于 for 循环内的行 wordList.erase 产生越界错误,所以我不能以这种方式删除重复的条目。 我也尝试了 unique() 方法,但这似乎不起作用,它只会删除一些条目。

将成对向量减少为唯一元素的最有效方法是什么?

【问题讨论】:

  • 你熟悉std::map吗?
  • 是的,但是我需要按降序打印此列表,如果我没记错的话,地图无法根据其中的某些值进行排序。我错了吗?
  • 当您从循环内的向量中删除元素时,您必须考虑到大小正在发生变化。如果你删除元素 i 那么下一个元素不是 i+1 而是 i.
  • 地图是按键排序的,你是对的。我不知道您还有什么其他要求,但我会考虑构建地图,然后将其转录为地图 以进行打印。
  • A std::map 不存储重复键。这些词是地图中的key 元素。就像mymap["the_word"]++; 将检测到“the_word”的次数加 1 一样简单。如果已经有一个带有键 "the_word" 的条目,它不会将另一个条目添加到地图中。

标签: c++ vector


【解决方案1】:

你可以使用类似的东西:

std::map<std::string, std::size_t>
compute_frequency(const std::vector<std::string>& words)
{
    std::map<std::string, std::size_t> res;

    for (const auto& word : words) {
        ++res[word];
    }
    return res;
}


void test(const std::vector<std::string>& words)
{
    const auto m = compute_frequency();
    std::vector<std::pair<std::string, std::size_t>> v(m.begin(), m.end());

    auto myless = [](const auto& lhs, const auto& rhs) {
        //return lhs.first > rhs.first;   // by decreasing word
                                          // (then you may add the comp in map directly)
        return lhs.second > rhs.second;   // by decreasing frequency
    };
    std::sort(v.begin(), v.end(), myless);
    for (const auto& p : v) {
        std::cout << p.first << " appears " << p.second << std::endl;
    }

);

【讨论】:

  • 谢谢,我确实使用了地图,并且可以使用它。当然,我现在在程序的其他部分遇到了 4 个其他问题,但我确实有一个简洁的单词列表及其频率
【解决方案2】:

您遇到问题,因为您在迭代向量时从向量中删除,这会改变列表的大小,并且您的 i++ 和 j++ 可以跳过条目,您会错过一些

您可能需要考虑使用 std::set 或在将其添加到向量之前执行 find() 以确定向量是否已包含单词

【讨论】:

    【解决方案3】:

    试试这个:

    for(int j = 0; j < wordList.size(); j++) {
        for(int k = j+1; k < wordList.size(); /*no increment*/) {
            if(wordList[j].first == wordList[k].first)
            {
                wordList[j].second++;
                wordList.erase(wordList.begin()+k);
            } else {
                k++;   // increment only if no element was erased !
            }
        }
    }
    

    当您在循环中擦除时,您必须考虑在擦除元素 k 之后,下一个是 k,而不是 k+1,即只有在没有元素被擦除时才必须递增。在不知道输入的情况下,很难说为什么会出现越界错误,但这就是原因。

    您也不必检查每对两次。第二个循环可以从 j+1 开始。

    PS:正如您在 cmets 中提到的那样,我还建议您改用 std::map。即使您之后需要一个向量(参见例如here)。

    【讨论】:

      猜你喜欢
      • 2021-02-24
      • 2014-06-02
      • 2016-09-19
      • 2014-05-05
      • 2018-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多