C++ 在 std::list 中查找所有匹配元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27454831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Find all matching elements in std::list
提问by lancery
I was wondering if there's any built-in or well-established way (i.e. via lambda) to go through the elements of an std::list and find all the ones that match a given value? I know I can iterate through all of them, but I thought I'd ask if there's a way to get an iterator that iterates through just the elements that match a given criteria? My sample below only gives me the iterator to the first matching element.
我想知道是否有任何内置或完善的方法(即通过 lambda)来遍历 std::list 的元素并找到所有与给定值匹配的元素?我知道我可以遍历所有这些,但我想我会问是否有办法让迭代器只遍历符合给定条件的元素?我下面的示例只给了我第一个匹配元素的迭代器。
#include <list>
#include <algorithm>
#include <stdio.h>
int main()
{
std::list<int> List;
List.push_back(100);
List.push_back(200);
List.push_back(300);
List.push_back(100);
int findValue = 100;
auto it = std::find_if(List.begin(), List.end(), [findValue](const int value)
{
return (value == findValue);
});
if (it != List.end())
{
for (; it != List.end(); ++it)
{
printf("%d\n", * it);
}
}
return 0;
}
Thanks for any feedback.
感谢您的任何反馈。
采纳答案by Jonathan Wakely
std::find_if
is a generalisation of std::find
for when you need a function to check for the elements you want, rather than a simple test for equality. If you just want to do a simple test for equality then there's no need for the generalised form, and the lambda just adds complexity and verbosity. Just use std::find(begin, end, findValue)
instead:
std::find_if
是std::find
for 当您需要一个函数来检查您想要的元素时的概括,而不是简单的相等性测试。如果您只想对相等性进行简单的测试,则不需要通用形式,而 lambda 只会增加复杂性和冗长性。只需使用std::find(begin, end, findValue)
:
std::vector<std::list<int>::const_iterator> matches;
auto i = list.begin(), end = list.end();
while (i != end)
{
i = std::find(i, end, findValue);
if (i != end)
matches.push_back(i++);
}
But rather than calling find
in a loop I'd just write the loop manually:
但不是find
在循环中调用,我只是手动编写循环:
std::vector<std::list<int>::const_iterator> matches;
for (auto i = list.begin(), toofar = l.end(); i != toofar; ++i)
if (*i == findValue)
matches.push_back(i);
回答by smac89
EDIT 17/05/20
编辑 17/05/20
With the advent of C++20 just around the corner, the standard library has now introduced the concept of rangeswhich are lazy views over collections and their transformations.
随着 C++20 的到来,标准库现在引入了范围的概念,范围是对集合及其转换的惰性视图。
This means you can now have a iterator that can be used to view a container which has been filtered and transformed, without having to create several iterators or even allocate memory.
这意味着您现在可以拥有一个迭代器,该迭代器可用于查看经过过滤和转换的容器,而无需创建多个迭代器甚至分配内存。
Having said that, this is a way to create an iterator over just the filtered elements of your list:
话虽如此,这是一种仅在列表的过滤元素上创建迭代器的方法:
auto matching_100 = List | std::views::filter([](auto &v) {
return v == 100;
});
How sweet is that? All you need to use all that?
那有多甜?所有你需要使用这一切?
#include <ranges>
Previous answer
上一个答案
#include <list>
#include <algorithm>
#include <iterator>
#include <iostream>
int main()
{
std::list<int> List;
List.push_back(100);
List.push_back(200);
List.push_back(300);
List.push_back(100);
int findValue = 100;
std::copy_if(List.begin(), List.end(), std::ostream_iterator<int>(std::cout, "\n"), [&](int v) {
return v == findValue;
});
return 0;
}
If you don't want to directly output the results and want to fill another container with the matches:
如果您不想直接输出结果并想用匹配项填充另一个容器:
std::vector<int> matches;
std::copy_if(List.begin(), List.end(), std::back_inserter(matches), [&](int v) {
return v == findValue;
});
回答by Pradhan
boost::filter_iterator
allows you to work with only the elements of a iterable that satisfy a predicate. Given a predicate Pred
and a container Cont
,
boost::filter_iterator
允许您仅使用满足谓词的可迭代元素。给定一个谓词Pred
和一个容器Cont
,
auto begin_iter = boost::make_filter_iterator(Pred, std::begin(Cont), std::end(Cont));
auto end_iter = boost::make_filter_iterator(Pred, std::end(Cont), std::end(Cont));
You can now use begin_iter
and end_iter
as if they were the begin and end iterators of a container containing only those elements of Cont
that satisfied Pred
. Another added advantage is that you can wrap the iterators in a boost::iterator_range
and use it in places which expect a iterable object, like a range-based for
loop like this:
您现在可以使用begin_iter
and end_iter
,好像它们是容器的开始和结束迭代器,只包含那些Cont
满意的元素Pred
。另一个附加优点是您可以将迭代器包装在 a 中boost::iterator_range
,并在需要可迭代对象的地方使用它,例如像这样的基于范围的for
循环:
auto range = boost::make_iterator_range(begin_iter, end_iter);
for(auto x : range) do_something(x);
In particular, setting Pred
to a functor(could be a lambda) that checks for equality with your fixed value will give you the iterators you need.
特别是,设置Pred
为检查与固定值相等的函子(可能是 lambda)将为您提供所需的迭代器。