【问题标题】:Using STL algorithm to find all matches in a set使用 STL 算法查找集合中的所有匹配项
【发布时间】:2017-11-06 16:39:07
【问题描述】:

我有一个包含 Song 对象的集合。 我想搜索所有出现的具有特定标题的歌曲。 我需要使用 STL 算法。

问题是当它找到第一个匹配项时它会停止搜索。

我正在尝试通过使用 while 循环并更改从何处开始搜索来修复它,但我无法让它工作。

原始函数

set<Song> SongLibrary::SearchSong(string title)
{
    set<Song> foundSongs;

    find_if(begin(m_songs), end(m_songs),[&](Song const& p)

        {
            if (p.getTitle() == title)
            {
                foundSongs.insert(p);
            }
            return p.getTitle() == title; });

    return foundSongs;
}

这是我尝试修改它以使用 while 循环

while (startSearch != m_songs.end)
{
    find_if(startSearch, end(m_songs), [&](Song const& p) // wont take start search as a parameter
    {
        if (p.getTitle() == title)
        {
            startSearch == m_songs.Position(); // this Line is wrong
            foundSongs.insert(p);
        }
        return p.getTitle() == title; });
}

尝试使用 Copy_if

copy_if(m_songs.begin(), m_songs.end(), foundSongs, [&](Song const& s), s.getTitle() == title);

【问题讨论】:

  • 而不是std::find_if,您似乎可以使用std::copy_if,因为这就是您真正在做的事情。
  • @tobi303 这是一个不同的问题,从那时起我一直在研究它以返回一个集合
  • std::find_if 在找到匹配项时停止搜索。这是设计使然,它将迭代器返回到容器中找到的第一个元素。您只是使用了错误的算法。在我看来,您将std::find_ifstd::for_each 混淆了。考虑使用 std::copy_if 代替另一条评论中提到的。
  • @FrançoisAndrieux 我目前正在尝试使用 copy_if,但是如何获得每首歌曲的标题? copy_if(m_songs.begin(), m_songs.end(), foundSongs, Song.getTitle() == title);
  • 你可以使用 std::multiset 和基于标题的比较器吗?

标签: c++ algorithm stl find


【解决方案1】:

对于这种情况,您通常希望使用std::copy_if

set<Song> SongLibrary::SearchSong(string title)
{
    set<Song> foundSongs;

    std::copy_if(begin(m_songs), end(m_songs), 
        std::inserter(foundSongs, end(foundSongs)),
        [&](Song const &s) { return s.getTitle() == title; });

}

[不相关:我使用了与问题中相同的签名,但至少值得考虑通过 const 引用而不是值传递参数。]

如果您将歌曲存储在序列容器中(例如,vectordeque),您可以改用 std::partition

auto pos = std::partition(begin(m_songs), end(m_songs), 
    [&](Song const &s) { return s.getTitle() == title; });

在这种情况下,[m_songs.begin(), pos) 是匹配请求的歌曲范围,[pos, m_songs.end()) 是不匹配的歌曲。

另请注意,set 按排序顺序存储项目。因此,如果 getTitle() 在对集合的成员进行排序时用作键(或至少是主键),您可能可以更有效地做一些事情——您可以使用集合的 equal_range 成员来找到所有具有相同标题的歌曲。这将为您提供具有对数复杂度的范围开始和结束的迭代器。然后您将复制该范围(具有线性复杂性),因此如果您关心的范围仅占整个集合的一小部分,这可能会显着提高速度。

【讨论】:

  • 谢谢,这解决了我的问题,并给了我一些非常有用的信息。 :)
【解决方案2】:

不幸的是,在像copy_if 这样的函数中,不能将std::back_inserter 用于没有push_back 函数的容器,而std::set 没有,但是您可以通过将其复制到向量。

// Suppose i want to copy all occurrences of 1
set<int> v{1, 2, 1, 4,1, 6, 1, 1, 9, 10};
vector<int> newSet;
std::copy_if(v.begin(),v.end(),std::back_inserter(newSet),[](int val) {  return val == 1;});

但是你为什么使用set。从代码来看,Songs 实例似乎不应该按排序顺序存储。

除非并且直到您需要按唯一元素的排序顺序存储 Songs,否则您可以使用“向量”来实现您想要做的事情

vector<int> v{1, 2, 1, 4,1, 6, 1, 1, 9, 10};
vector<int> newSet;
std::copy_if(v.begin(),v.end(),std::back_inserter(newSet),[](int val) { return val == 1;});

【讨论】:

    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多