Home > Software design >  How to find minimum value from vector with some condition?
How to find minimum value from vector with some condition?

Time:09-27

I need to get the min element value (x) in the vector.

Given the index i of the x, I need to check if the flag[I] == 0 to return I.

I don't want to sort or discard any value because I need its ordinal number, I need the vector to hold its "structure" how can I get the index of that min_element?

example

   A = {1, 2, 3, 4, 0, -1}
flag = {0, 0, 1, 0, 1, 1}

min_element = -1, but flag[5] = 1 same for element 0 so min_element is 1 and index 0

CodePudding user response:

You can have a filter view of A with only the elements where flag is 0, and pass that to std::ranges::min.

With C 23 range views:

namespace views = std::ranges::views;
// min is undefined if passed an empty range
assert(std::ranges::any_of(flag, [](auto f){ return f == 0; });
auto value = std::ranges::min(views::zip(A, flag)
                            | views::filter([](auto && item){ return std::get<1>(item) == 0; })
                            | views::transform([](auto && item){ return std::get<0>(item); }));

See it on godbolt

CodePudding user response:

If you store both arrays in a single std::vector<std::pair<int,int>> you can use std::min_element directly:

#include <vector>
#include <iostream>
#include <algorithm>

int main() {
    std::vector<int> A    = {1, 2, 3, 4, 0, -1};
    std::vector<int> flag = {0, 0, 1, 0, 1, 1};

    std::vector<std::pair<int,int>> flag_and_A;
    for (int i=0;i<A.size();  i){
        flag_and_A.push_back({flag[i],A[i]});
    }
    auto it = std::min_element(flag_and_A.begin(),flag_and_A.end());
    std::cout << it->second;
}

Live Demo

std::pair::operator< induces a lexicographical odering, ie first first (the flag) is compared then second (A). In other words, entries with flag == 0 are considered smaller than entries with flag == 1.

If you do not want to construct the vector<pair<int,int>> you can still use std::pair::operator<:

int main() {
    std::vector<int> A    = {1, 2, 3, 4, 0, -1};
    std::vector<int> flag = {0, 0, 1, 0, 1, 1};


    auto it = std::min_element(A.begin(),A.end(),[&](const int& a,const int& b){
        unsigned index_a = &a - &A[0];
        unsigned index_b = &b - &A[0];
        return std::make_pair(flag[index_a],a) < std::make_pair(flag[index_b],b);
    });
    std::cout << *it;
}

Live Demo

CodePudding user response:

I think you can make a copy of the vector, to sort, record the min-element,and then clear the copy vector.

  • Related