Xavier Imbs
Xavier Imbs

Reputation: 212

Find the last non-zero element in a std::vector

I'm trying to find the index of the last non-zero element in a std::vector<double>. If the last element in the vector is non-zero then it should return the index of that last element.

I believe I can use std::find_if_not, reverse iterators and std::distance, based on this:

std::find_if_not(amounts.rbegin(), amounts.rend(), 0.0)

where amounts is a std::vector<double>, but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin().

Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?

I'm using C++11.

Upvotes: 2

Views: 3493

Answers (3)

marcinj
marcinj

Reputation: 50016

Example:

std::vector<double> v{1.32, 1.423, 2.543, 3.534, 4.2, 0};

auto result1 = std::find_if(std::rbegin(v), std::rend(v), [](auto& v) { return std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); } );
if (result1 != std::rend(v)) {
    std::cout << *result1 << "\n";
    std::cout << std::distance(std::begin(v), (result1 + 1).base());
}

outputs:

4.2
4

[edit]

more explanation on:

std::fabs(v - 0) > std::numeric_limits<double>::epsilon(); }

in OP question there was:

Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?

so this is such tolerance check, you can replace epsilon use with some other value.

Upvotes: 9

eerorika
eerorika

Reputation: 238401

but I'm having difficulty in combining this with std::distance and a forward iterator amounts.begin()

Reverse iterators have member function base that returns a non-reverse iterator with the relation &*(rit.base() - 1) == &*rit. So, you can use the following:

 std::distance(amounts.begin(), found.base()) - 1;

Another option:

 amounts.size() - std::distance(amounts.rbegin(), found) - 1

Also, is there a way I can introduce a predicate to compare on, say a tolerance of 1e-8?

Yes. In fact, you must use a predicate, even for the exact comparison, since that's what std::find_if_not expects as the third parameter (instead of value of an element).

Upvotes: 0

Tommy Andersen
Tommy Andersen

Reputation: 7220

A simple for loop can also do the trick, see live sample: http://ideone.com/dVNOKk

#include <iostream>
#include <vector>

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

    for (int i = static_cast<int>(v.size()) - 1; i >= 0; --i) {
        if (v.at(i) != 0) {
            std::cout << "Last non-zero at: " << i << '\n';
            break;
        }
    }
    return 0;
}

Output: Last non-zero at: 12

Upvotes: 0

Related Questions