5

I've got a C-style array called board that contains some char's. I'm trying to create a std::array or std::vector (either would be fine, although std::array would be preferable) to store all the indices of board that are a certain value (in my case, 0).
This code I wrote is functional and works well:

std::vector<int> zeroes;
zeroes.reserve(16);
//board has 16 elements, so zeroes.size() will never be larger than 16.
//I used this reserve for speedup - the compiler doesn't require it.
for (int i = 0; i < 16; ++i)
{
    if (board[i] == 0)
    {
        zeroes.push_back(i);
    }
}

However, from past experience, whenever a std function exists that could replace part of my code, it is terser and hence stylistically preferred and also faster. My function seems like a fairly basic operation - I know there is a standard function* to access the index of an array that contains a value when that value only occurs once** in the array. So, is there a standard function to create an array of the indices that contain a value, assuming that more than one such index exists?


* Technically, two nested function calls: int x = std::distance(board, std::find(board, board + 16, 0));. See the accepted answer here.
** Well, it still works if more than one index with the desired value is present, but it returns only the first such index, which isn't very useful in my context.


Edit: As one of the answers misunderstood the question, I'll clarify what I'm seeking. Let's say we have:

char board[16] = {0, 2, 0, 4,
                  2, 4, 8, 2,
                  0, 0, 8, 4,
                  2, 0, 0, 2};

Now, the indices which I'm looking for are {0, 2, 8, 9, 13, 14} because board[0] = 0, board[2] = 0, board[8] = 0, etc. and these are the only numbers which satisfy that property.

Community
  • 1
  • 1
QuantumFool
  • 609
  • 3
  • 10
  • 29
  • Boost.ranges can do that. – Baum mit Augen Jun 01 '16 at 00:55
  • I was thinking `boost::filter_iterator` – Mooing Duck Jun 01 '16 at 00:56
  • That code looks fine, except for the initial call to `zeroes.reserve(16)`. The calls to `push_back` will adjust the size of `zeroes` as needed, and when it's finished, `zeroes.size()` will tell you how many indices are there. – Pete Becker Jun 01 '16 at 00:57
  • 2
    @PeteBecker I put the reserve(16) in for computational speedup - that way, it doesn't have to waste time dynamically resizing the array when I already know an upper bound on the array's size. It works without the reserve, but I'll be calling this function frequently enough to make the reserve worth the typing - just edited the post to clarify – QuantumFool Jun 01 '16 at 01:01
  • Yes, calling `reserve()` is okay. Too long a day. – Pete Becker Jun 01 '16 at 01:30
  • 2
    Having now seen two answers with solutions that work, I'd stick with your original code. – Pete Becker Jun 01 '16 at 01:32

1 Answers1

6

Here's a solution using std::iota and std::remove_if:

#include <algorithm>
#include <iostream>

int main () {
  const std::size_t board_size = 16;
  char board [board_size] = {
    0, 2, 0, 4,
    2, 4, 8, 2,
    0, 0, 8, 4,
    2, 0, 0, 2
  };

  // Initialize a zero-filled vector of the appropriate size.
  std::vector<int> zeroes(board_size);

  // Fill the vector with index values (0 through board_size - 1).
  std::iota(zeroes.begin(), zeroes.end(), 0);

  // Remove the index values that do not correspond to zero elements in the board.
  zeroes.erase(std::remove_if(zeroes.begin(), zeroes.end(), [&board] (int i) {
    return board[i] != 0;
  }), zeroes.end());

  // Output the resulting contents of the vector.
  for (int i : zeroes) {
    std::cout << i << std::endl;
  }
}

Output of the program (demo):

0
2
8
9
13
14
Binary Birch Tree
  • 15,140
  • 1
  • 17
  • 13