Remove zero values from Eigen Vector

Hi,
For a program I am writing I want to obtain a Eigen::Vector with only the non zero values of another Eigen::Vector.
Lets say I have

Eigen:VectorXd myVec(9)
myVec << 1,0,3,0,0,6,8,0,9

and now I want myVecNew = 1,3,6,8,9

Is this possible without making use of a relative large piece of code with loops etc? Maybe something comparable to the nonzeros() function of Matlab

Thank you!

1
2
vec.erase( std::remove_if (vec.begin(), vec.end(), [](int val) {return  val == 0;}),
                vec.end());


The remove_if from <algorithm> rearranges the vector and returns an iterator to the new place that you want as the new end of the vector without zero values in it, and the erase function then resizes the vector to just contain the things you wanted.

This alters the vector. If you want to retain the original, you could make a copy of it first and then work on the copy, or you could get fancy and use the copy_if function to iteratte over the original vector and only copy the values you want to the new.
Last edited on
Hi, thanks for your answer, but I think this method is used for std::vectors, not for Eigen..
1
2
std::erase( std::remove_if (vec.begin(), vec.end(), [](int val) {return  val == 0;}),
                vec.end());


std::erase does require C++20

This does assume that this Eigen::vector classs you're using provides fairly standard container support.

If it doesn't, you'll have to read the Eigen documentation to see what equivalent functions they provide.

Alternatively, if the Eigen classes don't have any support for this, do what I originally suggested, but on a vector that you created from the Eigen::vector, and turn the result back into an Eigen::vector
Last edited on
Unfortunately I don't think I have C++20 available.

Ill try to look in the Eigen documentation and otherwise convert it to a vector and back, but this seems like quiet some code for such a small operation..
If this Eigen::vector object you have is meant to be used for linear algebra operations, with this object representing a mathematical vector, then simply removing all the zeroes from one doesn't make a lot of sense and thus wouldn't be supported.
Yeah I guess that is true.

Ill explain the situation in more detail:
I have a matrix with zero's and some non zero values, per row I want to loop over the non zero values in that row. I want to use every non zero value in each row to as an index for something else.
For example is some languages you can do the following:
indexVector = [ 1,2,3,4,5,6,7,8,9 ]
availability = [ 0,1,0,0,1,1,0,0,0]
for index in indexVector[availability]:
etc
which will make the program loop with index = 2, index = 5, index = 6

I was looking for something equivalent, but couldn't find it so I thought of a solution where I did indexVector.cwiseproduct(availability), giving indexAvailable= [ 0,2,0,0,5,6,0,0,0 ]. After this I wanted to remove the zeros (temp =[ 2,5,6] and do a simple loop with i=0; i<temp.size(); i++ and then use temp(i) to get 2 5 and 6 as index for something else.

Now that I am typing it, it sounds rather inefficient.
It might be a completely different question, but do you have a better approach?
I want to use every non zero value in each row to as an index for something else

If I don’t misunderstand your question, it seems Sparse matrix manipulations is what you’re looking for:
https://eigen.tuxfamily.org/dox/group__TutorialSparse.html
(see the very first example)

Let me add your first post would be easily solved by the standard library:
Lets say I have
Eigen:VectorXd myVec(9)
myVec << 1,0,3,0,0,6,8,0,9
and now I want myVecNew = 1,3,6,8,9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <valarray>


void print(const std::valarray<int>& what);


int main()
{
    std::valarray<int> v1 { 1, 0, 3, 0, 0, 6, 8, 0, 9 };
    std::cout << "v1:\n";
    print(v1);

    std::valarray v2 = v1[v1 != 0]; // just like that!
    std::cout << "v2:\n";
    print(v2);
}


void print(const std::valarray<int>& what)
{
    for(int i : what) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}


Output
v1:
1 0 3 0 0 6 8 0 9
v2:
1 3 6 8 9


indexVector = [ 1,2,3,4,5,6,7,8,9 ]
availability = [ 0,1,0,0,1,1,0,0,0]
for index in indexVector[availability]:

Like in:
1
2
3
4
5
6
for ( int dim=0; dim < N; ++dim ) {
  if ( availability[ dim ] ) {
    index = indexVector[ dim ];
    // use index
  }
}

C++20 ranges probably can hide that "if" into fancier syntax.
@Enoizat
I will look into the sparse methods, not sure if this will help me for this specific part, but I definitely need it later on, thank you!
The second method you're mentioning works for std, not for Eigen, so I firs have to convert to a std::valarray.
This can be done by using Map from Eigen and after this it has to be converted back, how is this done?
This could definitely be a solution, but still needs the conversion.

@keskiverto
This is also a nice work around thanks!

I will look what works the best for me
Last edited on
Topic archived. No new replies allowed.