Hum
Hum

Reputation: 484

Finding the indexes of all occurrences of an element in a vector

Suppose I have a vector A = {1 0 1 1 0 0 0 1 0}. Now I want to get the indexes of all occurrences of 0 returned as another vector B.

template< class InputIt, class T>
std::vector<int> IndicesOf(InputIt first, InputIt last, const T& value) {

}

Here is a start:

std::vector<int>::iterator iter = std::find_if(A.begin(), A.end(), 0);
B = std::distance(A.begin(), iter);

Upvotes: 23

Views: 25341

Answers (4)

Enlico
Enlico

Reputation: 28500

This solution is a bit longer if you consider #includes and usings, but that is irrelevant in bigger code bases.

Without those, and considering that one could store some useful function object like first and second in a header, the core part becomes a one liner:

auto result = enumerate(v) | filter(second_is_zero) | transform(first);

Defining second_is_zero is a bit overkill; defining auto constexpr equal_to = std::equal_to<>{}; instead, would lead to the following, which is still readable, once you get used to functional utilities such as compose and partial:

auto result = enumerate(v) | filter(compose(partial(equal_to, 0), second))
                           | transform(first);

Here's the complete code, though

#include <boost/hana/functional/compose.hpp>
#include <boost/hana/functional/partial.hpp>
#include <functional>
#include <iostream>
#include <vector>
#include <range/v3/view/enumerate.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>

using boost::hana::compose;
using boost::hana::partial;
using namespace ranges::views;

int main()
{
  std::vector<int> v{1,0,1,1,0,0,0,1,0};

  // define some useful function object
  auto constexpr first = [](auto const& pair){ return pair.first; };
  auto constexpr second = [](auto const& pair){ return pair.second; };
  auto constexpr second_is_zero = compose(partial(std::equal_to<>{},0), second);

  // oneline to get the result (it's in a view, not a vector)
  auto result = enumerate(v)           // attach indexes 0,1,2,... to the elements
              | filter(second_is_zero) // filter based on second
              | transform(first);      // extract the indexes

  // the following prints 14568
  for (auto i : result) {
    std::cout << i;
  }
  std::cout << std::endl;
}

Upvotes: 1

Darkproduct
Darkproduct

Reputation: 1243

To the answer of @some-programmer-dude with lamda:

#include <algorithm> //find_if

std::vector<int> A{1, 0, 1, 1, 0, 0, 0, 1, 0};
std::vector<int> B;

std::vector<int>::iterator it = A.begin();
while ((it = std::find_if(it, A.end(), [](int x){return x == 0; })) != A.end())
{
    B.push_back(std::distance(A.begin(), it));
    it++;
}

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409442

Just call std::find_if again, with the previously returned iterator (plus one) as the beginning. Do in a loop until std::find_if returns A.end().


Sample code

#include <algorithm> //find_if

bool isZero(int x){
    return x == 0;
}

std::vector<int>::iterator iter = A.begin();
while ((iter = std::find_if(iter, A.end(), isZero)) != A.end())
{
    // Do something with iter

    iter++;
}

Upvotes: 29

Carlson Bimbuh
Carlson Bimbuh

Reputation: 126

Try this: char c: element whose indexes you want to get. I used a string but this same code will work perfectly fine with a vector. vecky stores all the indexes found.

std::vector<int> getIndex(string s, char c)
{
    std::vector<int> vecky;

    for (int i = 0; i != s.length(); i++)
    {
        if (s[i] == c)
        {
            vecky.push_back(i);
        }
    }

    return vecky;
}

Upvotes: 2

Related Questions