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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:48:00  来源:igfitidea点击:

Find all matching elements in std::list

c++c++11stdlist

提问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_ifis a generalisation of std::findfor 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_ifstd::findfor 当您需要一个函数来检查您想要的元素时的概括,而不是简单的相等性测试。如果您只想对相等性进行简单的测试,则不需要通用形式,而 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 findin 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>

Try it out

试试看

Previous answer

上一个答案

Using copy_ifand iterators:

使用copy_if迭代器

#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_iteratorallows you to work with only the elements of a iterable that satisfy a predicate. Given a predicate Predand 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_iterand end_iteras if they were the begin and end iterators of a container containing only those elements of Contthat satisfied Pred. Another added advantage is that you can wrap the iterators in a boost::iterator_rangeand use it in places which expect a iterable object, like a range-based forloop like this:

您现在可以使用begin_iterand 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 Predto a functor(could be a lambda) that checks for equality with your fixed value will give you the iterators you need.

特别是,设置Pred为检查与固定值相等的函子(可能是 lambda)将为您提供所需的迭代器。