【问题标题】:Filter Lists for Repeats - List Deduplication过滤重复列表 - 列表重复数据删除
【发布时间】:2015-01-06 06:12:49
【问题描述】:

我有一些分布在多个文件中的单词列表,我需要一种快速的方法将它们全部合并到一个文件中。我想在合并时删除重复项,以便最终列表不包含单个单词的多个实例。

示例:

文本文件list_a.txt 内容如下:

apple
pear
peach

文本文件list_b.txt 内容如下:

foo
bar
peach
car

合并后,输出文件应显示:

apple
pear
peach
foo
bar
car

请注意,list_a.txtlist_b.txt 都包含单词 peach,但它只在输出文件中出现一次。

这是我使用的代码:

int main()
{
    string myList = "";
    string myFiles[] = {"list_a.txt", "list_b.txt"};
    string line;
    int iterationsSinceSleep = 0;
    size_t length = sizeof(myFiles)/sizeof(myFiles[0]);
    for(unsigned int i = 0; i < length; i++){
        cout<<"Starting " << myFiles[i] << endl;
        ifstream myfile((string("C:/words/").append(myFiles[i])).c_str());
        if (myfile.is_open())
        {
            while ( getline (myfile,line) ){
                string trimmedLine = trim(line);
                if(myList.find(trimmedLine) == string::npos){
                    myList.append(trimmedLine + '\n');
                }

                iterationsSinceSleep++;
                iterationsSinceSleep %= 10000;
                // Save the CPU!
                if(iterationsSinceSleep == 0) Sleep(10);

            }
            myfile.close();
        }else{
            cout << "Could not open & process " << myFiles[i] << endl;
        }
        Sleep(75); // Save the CPU!
        iterationsSinceSleep = 0;
    }

    // write to the file
    ofstream myfile ("C:/words/merged/final.txt");
    if (myfile.is_open())
    {
        cout<<"Writing filtered list"<<endl;
        myfile << myList;
        myfile.flush();
        myfile.close();
    }else{
        cout<<"Could not save filtered list."<<endl;
    }



    return 0;
}

这适用于较小的列表/文件,但我的一个列表有几百万行。

我需要一种方法让这段代码运行良好,即使它必须处理数百万行的多个文件。

我改进这一点的第一个想法是使用数组或向量而不是字符串来存储唯一行。但是,这两种方法各有优缺点。

使用数组的优点:

  • 更快的比较检查(我认为)
  • 更快的元素访问

使用数组的缺点:

  • 重新分配以插入新字符串可能会很慢
  • 程序必须跟踪数组的长度(不是大问题,而是一个因素)

使用向量的优点:

  • 动态添加元素
  • 内置搜索功能

使用向量的缺点:

  • 向向量中插入元素很慢(所以我读过)
  • 我认为向量的开销更大。

任何人都可以提供改进此代码并更有效地编写它的建议吗?速度是一个主要问题,但我还需要考虑内存消耗。

提前谢谢你。

【问题讨论】:

  • 不要使用数组。如果您确实存储它,请使用不允许重复的数据结构,2 只鸟 1 块石头。
  • 我认为 trie 结构可以很好地处理这类事情,它可能会产生很大的内存开销,具体取决于您的实现方式,但速度非常快,特别是在单词非常大的情况下
  • 好吧,例如向量的分配方案是开箱即用的。你可以通过复制来做同样的事情,但问题就来了——为什么在已经完成的时候还要这样做?
  • 阅读vector 以了解向量的分配。
  • @SpencerGrantDoak 对不起我的意思很短,平均单词的长度决定了树的高度,我会更新我的评论

标签: c++ arrays performance merge array-merge


【解决方案1】:

使用std::set。集合不允许重复条目。尝试类似:

std::set<std::string> mySet;
...
mySet.insert(trimmedString);
...
for (auto &&str : mySet)
   myFile << str;

注意:我只是在这里输入的,所以可能有一些错别字。

另请注意:这将对输出进行排序,不确定您是否想要。

【讨论】:

  • 排序没问题,只要它快速高效。我喜欢这个主意。我一定会调查std::set
  • 查找是 O(log n),插入可能很慢(ish),因为所有对象都是单独分配的,但通常比尝试保持数组或向量排序要快得多。它还使您的代码更简单(例如,您可以直接调用 insert 而无需检查它是否已经在集合中)。
  • 如果不关心订单,unordered_set 可能会更快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 2012-12-12
  • 2012-11-13
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
相关资源
最近更新 更多