使用STL算法查找集合中的所有匹配项

时间:2017-11-06 16:39:07

标签: c++ algorithm stl find

我有一个包含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);

2 个答案:

答案 0 :(得分:1)

不幸的是,在像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`来实现您尝试执行的操作

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;});

答案 1 :(得分: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()作为键(或至少是主键),则可以更有效地执行操作 - 您可以使用集合{{1找到所有具有相同标题的歌曲的成员。这将为您提供具有对数复杂度的范围的开头和结尾的迭代器。然后,您将复制该范围(线性复杂度),因此,如果您关注的范围仅占整个范围的一小部分,则可以显着提高速度。