使用 STL 算法查找集合中的所有匹配项
Posted
技术标签:
【中文标题】使用 STL 算法查找集合中的所有匹配项【英文标题】:Using STL algorithm to find all matches in a set 【发布时间】: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_if
与std::for_each
混淆了。考虑使用 std::copy_if
代替另一条评论中提到的。
@FrançoisAndrieux 我目前正在尝试使用 copy_if,但是如何获得每首歌曲的标题? copy_if(m_songs.begin(), m_songs.end(), foundSongs, Song.getTitle() == title);
你可以使用 std::multiset 和基于标题的比较器吗?
【参考方案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 引用而不是值传递参数。]
如果您将歌曲存储在序列容器中(例如,vector
或 deque
),您可以改用 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> v1, 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> v1, 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;);
【讨论】:
以上是关于使用 STL 算法查找集合中的所有匹配项的主要内容,如果未能解决你的问题,请参考以下文章
Groovy集合遍历 ( 使用集合的 findAll 方法查找集合中符合匹配条件的所有元素 | 代码示例 )