0

In C++, is there a way to create a new array from an old array with the old array only having those values from indices that satisfy a condition?

For instance, say we have

float A[10] ;    

and the indices, in this case, are idx=0,1,2,3,4,5,6,7,8,9.

I'd like to iterate, in a single-pass over these indices, checking a condition, say

idx >0 && idx < 8  

and so I obtain a new float array, say

float B[8]    

Numbered just the way you'd expect, idx_new=0,1,2,3,4,5,6,7, but only having the values from A of A[1], A[2],.. A[7].

I ask this because in the problem I'm working on, I have a 2-dimensional so-called "staggered grid", laid out in a 1-dimensional float array, and I want a new array with only the "inner cells." For example, I begin with a 5x6 staggered grid. It's represented by a float A[30] array of 30 floats. I can imagine this A to be a 2 dimensional grid with x-coordinate x=O,1,2,3,4 and y-coordinate y=0,1,2,3,4,5. I can access it's value on A through the (arithmetic) formula x+5*y, i.e.

A[x+5*y] ; // gets the value I want  

But now, I want a new array of only "inner cells" that excludes the grid points along the 4 "walls." So 0< x' < 4 and 0

Advice and discussions on how to implement this, utilizing good C++11/14 practices and fancy iterators, functors, and general advice on how to approach this kind of problem with the new features from C++11/14, would help me.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • You can't create a named array like this, but you can create a named std::vector, which is probably what you should have been using in the first place. –  Apr 17 '17 at 18:33
  • @NeilButterworth I had also asked for the fancy iterator or how to iterate in a single pass, to "slice" for the array values with indices that satisfy a condition. I would've wanted to know how to do this, because whether the data is represented by a float array or std::vector, I'd still don't know how to make such an iterator that's conditional on some condition. – ernestyalumni2014 Apr 17 '17 at 18:37
  • heard about `std::transform` nad lambdas? I can see a solution using those two – Fureeish Apr 17 '17 at 18:49
  • @Fureeish std::transform I don't know, looking it up right now, thanks! I've Google searched all kinds of permutations of search terms of the question I asked, and your suggestion of std::transform and someone else's, with std::copy_if is "yielding fruit" for my problem; I wouldn't have know to search for std::transform and std::copy_if without asking here; thanks! – ernestyalumni2014 Apr 17 '17 at 19:06
  • No problem. Keep in mind that things like `std::transform` or `std::copy_if` use functors as arguments. I encourage you to read about lambdas as well, since they allow to create anonymous functors that keep the code in one place and increase readability. – Fureeish Apr 17 '17 at 19:14
  • _"Advice and discussions"_" _"General advice"_ This is a Q&A repository, not a discussion forum. – Lightness Races in Orbit Apr 18 '17 at 00:55

1 Answers1

0

Posting here in stackoverflow helped because, believe me, I searched on Google many search term permutations for the question I had originally asked, but the suggestions ** std::transform** and ** std::copy_if ** (thanks to @jwimberley but he/she deleted his/her original answer, but std::copy_if helped alot) helped greatly in what to search for (use of std::copy_if isn't "advertised" enough, probably).

Those Google searches led me to @Mikhail 's answer, which is exactly what I needed, to take a subset of an array, to make a new array. cf. How to obtain index of element from predicate passed to some STL algorithm?

Given these arrays/vectors (I'm filling up "boilerplate", test values:

float A[10] { 11.,22.,33.,44.,55.,66.,77.,88.,99.,100.};
float B[8] = { 0. };
std::vector<float> A_vec(A,A+10);
std::vector<float> B_vec(B,B+8);  

then this is the important step:

auto iter = std::copy_if( A_vec.begin(), A_vec.end(), B_vec.begin(), 
   [&A_vec] (const float& x) -> bool { // <-- do not forget reference here
    size_t index = &x - &A_vec[0]; // simple, "textbook" manner to get the index
    std::cout << index << " ";
    bool condition = ((index >0) && (index <9));
    return condition; } );

which results in, for B_vec

// [ 22 33 44 55 66 77 88 99 ] // success!  

For the application I had, from going from a staggered grid to its inner cells, I did this - given

std::vector<float> staggered_grid(5*6) ; // 30 elements, each initialized to 0;
std::vector<float> inner_cells(3*4  ); // 12 elements, each initialized to 0   

for (int idx=0; idx<5*6;++idx) {
     staggered_grid[idx] = ((float) idx+10.f) ;}

and so the important step is

auto iter2d = std::copy_if( staggered_grid.begin(), staggered_grid.end(), inner_cells.begin(), 
[&] (const float& x) -> bool {          // <- do not forget reference here
       size_t index = &x - &staggered_grid[0]; // simple, "textbook" manner to get the index
       int j = index/5;
       int i = index % 5;
       bool condition = ((i>0) && (i<5-1) && (j>0) && (j<6-1));
       return condition; } );   

and so the result was

10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25 26 27 28 29
30 31 32 33 34
35 36 37 38 39

->

16 17 18
21 22 23
26 27 28
31 32 33

Community
  • 1
  • 1