【问题标题】:Qt C++11 string lists intersection via substring comparationQt C++11字符串通过子字符串比较列出交集
【发布时间】:2020-04-28 00:58:39
【问题描述】:

我对字符串列表比较有一些问题。我需要达到良好的性能,所以我搜索了几种方法,现在我尝试使用 std::set_intersection 来实现。

主要问题是我需要通过子字符串比较这些,例如我有这个列表:

1

111111
111222
222333
333444

2

444111
555222
666333
777444
555111
222111
111555

假设我使用了过滤器,它将从这些字符串的前 3 位数字中生成 substr(例如,我刚刚完成了这个函数)。结果我需要得到那个交叉点:

111111
111222
111555
222111
222333

现在我的代码如下所示:

QSharedPointer<QStringList> Intersection_Op::compute(QSharedPointer<QStringList> leftList,
                                                     QSharedPointer<QStringList> rightList,
                                                     QPair<int, int> filters)
{
    if (!leftList or !rightList)
        return QSharedPointer<QStringList>( nullptr );
    
    std::sort( leftList->begin(), leftList->end() );
    std::sort( rightList->begin(), rightList->end() );

    // std::string getCheckBody( const QString* str, QPair<int, int> filters )
    
    auto leftStdList = new std::list<QString>( leftList );
    auto rightStdList = new std::list<QString>( rightList );
    auto result = QSharedPointer<QStringList>( new QStringList() );

    std::set_intersection(leftStdList->begin(), leftStdList->end(),
                          rightStdList->begin(), rightStdList->end(), std::back_inserter( *result ),
                              [=] (const QString& one, const QString& two) -> bool {
         auto o = getCheckBody( one, filters );
         auto t = getCheckBody( two, filters );

         // got this condition from another thread here
         return  ( o.size() == t.size() )
                 ? (o < t)
                 : ( o.size() < t.size() );
    });

    delete leftStdList;
    delete rightStdList;
    
    return result;
}

现在我得到了这个结果:

111111
222333

首先,忽略第一个列表中具有相同数据的其他值,其次,忽略第二个列表。第二个可以通过使用切换列表复制此功能来解决。但是,我如何才能将我需要的所有值包含在一个列表中(至少)?

我之前从未在算法中使用过比较函数,特别是对于字符串比较,我怀疑我为此使用了错误的条件。也许我使用了错误的方法(std::set_intersection)?

关于数据大小,通常是~100k字符串列表,所以我真的在寻找如何优化这个任务。

你能帮我找到解决办法吗?任何人都可以为这项任务提供一些建议吗?

谢谢

【问题讨论】:

  • 您的代码不是 MVE,因此无法真正知道主要问题是否在您提供的代码中。但是,如果它是关于运行算法需要多少内存,那么您必须担心我们只能假设存在的内存泄漏:您到底为什么使用 new 而没有 delete ?你为什么要使用 new ???
  • 对不起,我认为不需要在这篇文章中添加,但如果上下文很重要,我添加了完整的测试方法代码。是的,我知道我在这里使用 std 和 qt 东西,只是我现在测试算法,并编辑以前使用 Qt 东西的版本。
  • 不需要所有这些指针,std::list&lt;QString&gt; leftStdList(leftList); 就可以了。
  • @Jarod42 根本不需要leftStdList
  • 看来std::set_intersection 只捕获独特的交叉点。即使不应该这样做。

标签: c++ algorithm qt c++11 std


【解决方案1】:

std::set_intersection 是错误的方法。

如果某个元素在[first1, last1) 中出现m 次,在[first2, last2) 中出现n 次,则第一个std::min(m, n) 元素将从第一个范围复制到目标范围。

“111...”在一个中出现两次,在另一个中出现一次,“222...”在每个中出现一次。

你需要类似的东西

template<class InputIt1, class InputIt2,
         class OutputIt, class Compare>
OutputIt my_intersection(InputIt1 first1, InputIt1 last1,
                         InputIt2 first2, InputIt2 last2,
                         OutputIt d_first, Compare comp)
{
    while (first1 != last1 && first2 != last2) {
        auto range1 = std::equal_range(first1, last1, *first2, comp);
        auto range2 = std::equal_range(first2, last2, *first1, comp);

        d_first = std::copy(range1.first, range1.second, d_first);
        d_first = std::copy(range2.first, range2.second, d_first);

        first1 = range1.second;
        first2 = range2.second;
    }
    return d_first;
}

请注意,您需要按比较函数对输入进行排序。如果&lt; 对您的 lambda 给出不同的顺序,则您的代码格式错误,例如如果你想通过后缀而不是前缀进行比较。

【讨论】:

  • 非常感谢导航和这个例子:),最后我重新设计了这个变体,我还需要像你说的那样对列表进行排序。但在某些情况下,您的变体可能会丢失数据,因为只是可以跳过其中一个列表。 ( first1 / first 2 = range1 / range2.second )。 P.S:如何在此评论中添加代码?我只是这里的新手 xD。
  • @std-glimmer 这就是我们推进循环的方式。结束迭代器始终是我们感兴趣的元素的一个过去。您可以在 cmets 中使用` for code
猜你喜欢
  • 2022-11-28
  • 1970-01-01
  • 2020-08-23
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 2016-02-08
  • 2013-11-22
  • 1970-01-01
相关资源
最近更新 更多