ArgMin for vector<double> in C++? - c++

I'd like to find the index of the minimum value in a C++ std::vector<double>. Here's a somewhat verbose implementation of this:
//find index of smallest value in the vector
int argMin(std::vector<double> vec)
{
std::vector<double>::iterator mins = std::min_element(vec.begin(), vec.end()); //returns all mins
double min = mins[0]; //select the zeroth min if multiple mins exist
for(int i=0; i < vec.size(); i++)
{
//Note: could use fabs( (min - vec[i]) < 0.01) if worried about floating-point precision
if(vec[i] == min)
return i;
}
return -1;
}
(Let me know if you notice any mistakes in the above implementation. I tested it, but my testing is not at all exhaustive.)
I think the above implementation is probably a wheel-reinvention; I'd like to use built-in code if possible. Is there a one-line call to an STL function for this? Or, can someone suggest a more concise implementation?

You could use the standard min_element function:
std::min_element( vec.begin(), vec.end() );
It returns an iterator to the minimum element in the iterator range. Since you want an index and you are working with vectors, you can then substract the resulting iterator from vec.begin() to get such index.
There is an additional overload for a function or function-object if you need a custom comparison.

Related

Using std::find_if with std::vector to find smallest element greater than some value

I have a vector of doubles which are ordered.
std::vector<double> vec;
for(double x{0.0}; x < 10.0 + 0.5; x += 1.0) vec.push_back(x);
I am trying to use std::find_if to find the first element, and its corresponding index, of this vector for which y < element. Where y is some value.
For example, if y = 5.5 then the relevant element is element 6.0 which has index 6, and is the 7th element.
I suspect that a lambda function could be used do to this.
Can a lambda function be used to do this?
If so, how do I implement a find_if statement to do what I want?
1 line of code is necessary, if a lambda function is used: x is a local double (value we are searching for) const double x = 5.5
std::find_if(vec.cbegin(), vec.cend(), [x] (double element) { return (x < element); })
Breaking this down, we have:
std::find_if(vec.cbegin(), vec.cend(), lambda)
The lambda is:
[x] (double element) { return (x < element); }
This means:
capture the local variable x for use inside the lambda body
the lambda function takes a single double as an argument (the algorithm find_if will pass each element as it iterates over the vector to this function as element)
the function body returns true when the first element is found for which x < element
Note: I answered this question myself while researching possible solutions. The context in which I am using this in my own program is slightly different. In my context, the vector is a specification for numerical boundries, and I am looking to find lower < x < higher. Therefore the code I used is slightly different to this, in that I had to shift my returned iterator by 1 place because of how the numerical boundries are specified. If I introduced a bug in transcribing the solution, let me know.
Just use std::upper_bound() - it is more effective (it is using binary search) and does not need a lambda:
auto it = std::upper_bound( vec.begin(), vec.end(), x );
if you need to find lower < x < upper you can use std::equal_range(), but you would need additional logic to find proper lower as std::lower_bound will give element which less or equal to x, so you need to make sure lower is less than x and not equal.
live example
Looks like you haven't been introduced to std::upper_bound yet:
std::upper_bound(vec.begin(), vec.end(), x);
If you need the index, you can add a counter.
Something like
x = 5;
cnt = -1;
std::find_if(vec.cbegin(), vec.cend(),
[&] (double element) { ++cnt; return (x < element); })

Sort std::vector<int> but ignore a certain number

I have an std::vector<int> of the size 10 and each entry is initially -1. This vector represents a leaderboard for my game (high scores), and -1 just means there is no score for that entry.
std::vector<int> myVector;
myVector.resize(10, -1);
When the game is started, I want to load the high score from a file. I load each line (up to 10 lines), convert the value that is found to an int with std::stoi, and if the number is >0 I replace it with the -1 currently in the vector at the current position.
All this works. Now to the problem:
Since the values in the file aren't necessarily sorted, I want to sort myVector after I load all entries. I do this with
std::sort(myVector.begin(), myVector.end());
This sorts it in ascending order (lower score is better in my game).
The problem is that, since the vector is initially filled with -1 and there aren't necessarily 10 entries saved in the high scores file, the vector might contain a few -1 in addition to the player's scores.
That means when sorting the vector with the above code, all the -1 will appear before the player's scores.
My question is: How do I sort the vector (in ascending order), but all entries with -1 will be put at the end (since they don't represent a real score)?
Combine partitioning and sorting:
std::sort(v.begin(),
std::partition(v.begin(), v.end(), [](int n){ return n != -1; }));
If you store the iterator returned from partition, you already have a complete description of the range of non-trivial values, so you don't need to look for −1s later.
You can provide lambda as parameter for sort:
std::sort(myVector.begin(), myVector.end(),[]( int i1, int i2 ) {
if( i1 == -1 ) return false;
if( i2 == -1 ) return true;
return i1 < i2; }
);
here is the demo (copied from Kerrek)
but it is not clear how you realize where is which score after sort.
From your description, it appears that the score can be never negative. In that case, I'd recommend the scores to be a vector of unsigned int. You can define a constant
const unsigned int INFINITY = -1;
and load your vector with INFINITY initially. INFINITY is the maximum positive integer that can be stored in a 32 bit unsigned integer (which also corresponds to -1 in 2's complement)
Then you could simply sort using
sort(v.begin(),v.end());
All INFINITY will be at the end after the sort.
std::sort supports using your own comparison function with the signature bool cmp(const T& a, const T& b);. So write your own function similar to this:
bool sort_negatives(const int& a, const int& b)
{
if (a == -1) {
return false;
}
if (b == -1) {
return true;
}
return a < b;
}
And then call sort like std::sort(myVector.begin(), myVector.end(), sort_negatives);.
EDIT: Fixed the logic courtesy of Slava. If you are using a compiler with C++11 support, use the lambda or partition answers, but this should work on compilers pre C++11.
For the following, I assume that the -1 values are all placed at the end of the vector. If they are not, use KerrekSB's method, or make sure that you do not skip the indices in the vector for which no valid score is in the file (by using an extra index / iterator for writing to the vector).
std::sort uses a pair of iterators. Simply provide the sub-range which contains non--1 values. You already know the end of this range after reading from a file. If you already use iterators to fill the vector, like in
auto it = myVector.begin();
while (...) {
*it = stoi(...);
++it;
}
then simply use it instead of myVector.end():
std::sort(myVector.begin(), it);
Otherwise (i.e., when using indices to fill up the vector, let's say i is the number of values), use
std::sort(myVector.begin(), myVector.begin() + i);
An alternative approach is to use reserve() instead of resize().
std::vector<int> myVector;
myVector.reserve(10);
for each line in file:
int number_in_line = ...;
myVector.push_back(number_in_line);
std::sort(myVector.begin(), myVector.end());
This way, the vector would have only the numbers that are actually in file, no extra (spurious) values (e.g. -1). If the vector need to be later passed to other module or function for further processing, they do not need to know about the special nature of '-1' values.

Getting minimum values and index from a matrix without repeating index C++

I have a vector< vector <int> > matrix of size n and I want to get the minimum value for each i and it indexs [i][j] and put it on a vector but I don't want to get any indexs repeated.
I've found a theoretical way but I cannot write it in code.
Make 2 vectors U←{1,...,n}, L←{1,...,n}
Repeat n times
Be (u,l)∈U×L from matrix[u,l] ≤ matrix[i,j], ∀i∈U, ∀j∈L
S[u] ← l
Do U←U-{u} y L←L-{l}
You can code this algorithm directly
typedef vector<vector<int>> Matrix;
typedef pair<size_t, size_t> Index;
typedef vector<Index> IndexList;
IndexList MinimalSequence(const Matrix& matrix) {
IndexList result;
set<size_t> U, L;
for (size_t i = 0; i < matrix.size(); ++i) { // consider square
U.insert(i);
L.insert(i);
}
while (U.size()) { // same as L.size()
int min = numeric_limits<int>::max();
Index minIndex;
for (auto u: U)
for (auto l: L)
if (matrix[u][l] < min) {
minIndex = make_pair(u, l);
min = matrix[u][l];
}
U.erase(minIndex.first);
L.erase(minIndex.second);
result.push_back(minIndex);
}
return result;
}
also your question is not clear in this way: do you want to start from the overall smallest element of the matrix (as your formula said) and then move to the next smallest?
or do you want to move through the columns from left to right? I implemented it according to formulas.
Note that set of non-negative integers in your formula is set<size_t> on which insert() and erase() are available. For all is while-loop
I would also suggest to try alternative algorithm - sort a list of matrix indices by there corresponding values and then iterate over it removing indices you dont want anymore.
edit: code actually differs from algorithm in few ways to be precise. That seemed more practical.
process is repeated until set of indices is exhausted - that is equal to n
return structure is list of 2d indices and encodes more information than array
You already have accepted an answer, but aren't you facing the Assignment problem that can be solved using the Hugarian algorithm, and maybe even more efficient algorithms that exists and are already implemented?

Find n largest values in a vector

I currently have a vector and need to find the n largest numbers in it. For example, a user enters 5, i gotta run through it and output the 5 largest. Problem is, i can not sort this vector due to other constraints. Whats the best way to go about this?
Thanks!
Based on your description of not modifying the original vector and my assumption that you want the order to matter, I suggest std::partial_sort_copy:
//assume vector<int> as source
std::vector<int> dest(n); //largest n numbers; VLA or std::dynarray in C++14
std::partial_sort_copy(
std::begin(source), std::end(source), //.begin/.end in C++98/C++03
std::begin(dest), std::end(dest),
std::greater<int>() //remove "int" in C++14
);
//output dest however you want, e.g., std::copy
Is copying and sorting an option? I mean if your application is not that performance critical, this is the simplest (and asymptotically not too bad) way to go!
Something like this (A is incoming vector, N the number largest you want to find, v becomes the result vector):
vector<T> v(N, 0);
for each element in A:
if (element > v[N-1])
for(i = N-1; i > 0 && v[i] < element; i--)
v[i] = v[i-1];
v[i] = element;
This is some sort of "pseudo-C++", not exactly C++, but hopefully describes how you'd do this.

Why can't I delete last element of vector

I have stl vector consisting of several elements. I need to iterate through this vector and delete elements which meets some criteria. So I wrote this code
for (int j = imageDataVector.size()-1; j >= 0; j--) {
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.end() - j);
}
This code works fine for almost all cases, however if all elements of vector meets the criteria I get an error:
vector erase iterator outside the range
This error occurs if I have only one element left in the vector. What do I do wrong ?
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.end()-j);
Should likely be:
if(imageDataVector[j] < threshold)
imageDataVector.erase(imageDataVector.begin()+j);
EDIT: for completeness, the erase-remove way and the iterator way:
imageDataVector.erase(std::remove_if(imageDataVector.begin(), imageDataVector.end(), std::bind2nd(std::less<vector_data_type>(), threshold)), imageDataVector.end());
vector<type>::iterator it = imageDataVector.begin();
while (it != imageDataVector.end()) {
if (*it < threshold)
it = imageDataVector.erase(it);
else
++it;
}
You're mixing forward and backward indexing.
I'd consider using std::remove_if instead. That way if you're removing multiple elements you don't shift the entire vector forwards on each erase.
It would look something like this:
imageDataVector.erase(std::remove_if(imageDataVector.begin(), imageDataVector.end(), std::bind2nd(std::less<data_type>(), threshold)), imageDataVector.end());
Alternately try the following, noting that it will result in a lot of movement if you remove multiple items from the vector.
for (int j=imageDataVector.size()-1 ;j>=0;j--)
{
if(imageDataVector[i] < threshold)
imageDataVector.erase(imageDataVector.begin()+j);
}
You're trying to count down j to zero, and imageDataVector.end() - 0 is not a valid iterator. In the standard C++ library containers, the end iterator points one past the last element, not at the last element.