Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all matching elements in std::list

Tags:

c++

c++11

stdlist

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.

#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.

like image 450
lancery Avatar asked Dec 13 '14 02:12

lancery


1 Answers

Updated answer

With the advent of C++20 just around the corner, the standard library has now introduced the concept of ranges which comes with view adapters and are simply lazy views over collections and their transformations.

This means you can now have an "iterator" which can be used to obtain a filtered and transformed view of an underlying container/collection, without having to create several iterators or even allocate memory.

Having said that, this is a way to create a view over just the filtered elements of your list:

// List is your std::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_if and iterators:

#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;
});
like image 84
smac89 Avatar answered Oct 06 '22 00:10

smac89