Find max values in a map from key pair first - c++

this is the first time for me to post something, so apologies if the formatting isn't correct or the question is framed incorrectly - I will take any feedback on those elements so I can improve.
I have a map created:
std::map<std::pair<int, int>, int> matchedBoxesCount;
I have populated it and when I iterate over it with:
for(auto it = matchedBoxesCount.cbegin(); it != matchedBoxesCount.cend(); ++it)
{
std::cout << it->first.first << " " << it->first.second << " " << it->second << ",";
}
The result is:
0 0 168, 0 1 8, 0 2 7, 0 3 7, 0 4 1, 0 5 9, 3 0 6, 3 1 41, 3 2 1, 3 3 3, 3 5 4, 3 6 2, 4 0 22, 4 1 1, 4 2 45, 4 3 7, 4 5 3, 4 9 2
I would like to filter this map into a simple map of pairs based on the value field of the key pair.
so based on highest value of each different first.first - so unique firsts 0, 3, 4
0 0 168 - is highest for 0 first field
3 1 41 - is highest for 3 first field
4 2 45 - is highest for 4 first field
copy these into a new map:
std::map<int,int> topScores;
int prevValuefirst = -1;
int currentMax = 0;
for(auto it = matchedBoxesCount.cbegin(); it != matchedBoxesCount.cend(); ++it) {
if (it->first.first == prevValuefirst){
if(it->second > currentMax){
currentMax = it->second;
topScores.at(prevValuefirst) = it->first.second;}
} else {
prevValuefirst = it->first.first;
topScores[prevValuefirst] = it->first.second;
currentMax = it->second;
}
}
it appears to work, but the map isn't sorted prior so this solution would fall over if a 'first.first' element appeared later in the list.
Is there a better way to do this? Should a sort be applied prior to make sure?
Thank you

Related

How can one find all the adjacent vertices, given a table of vertices with a specific rectangle format?

If I have a table of vertexes represented by:
a b c d
e f g h
i j k l
m n o p
How can I get the adjacencies of a node as indexes, if the indexes for this table is as follows:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
For example, node "a" should result: 1, 4, 5. node "f" results in 0, 1, 2, 4, 6, 8, 9, 10.
How can this be expanded to a table of any size? This is a 4x4, what about a 10x10? 3x4?
Can this be found with code? c++ preferred.
So far I tried: Since it's a 4x4 I tried subtracting 4 and adding 4 from the index of the node in question. However, this does not work for every node, especially the edge and corner nodes.
Here, every node is connected to 8-directional way. So we will try to get grid number of 8 adjacent cells.
// starting from upper left corner for a cell
int dr[8] = {-1, -1, -1, 0, 1, 1, 1, 0}; // 8 direction row
int dc[8] = {-1, 0, 1, 1, 1, 0, -1, -1}; // 8 direction column
int n = 20;
int m = 30;
int r = 1, c = 1; // position of 'f' is (1, 1)
for(int i = 0; i < 8; i++) {
int adjr = r + dr[i];
int adjc = c + dc[i];
if (adjr < 0 || adjr >= n || adjc < 0 || adjc >= m) continue; // check for invalid cells
cout << adjr << " " << adjc << endl; // {row, column} which is connected
}
Outputs:
0 0
0 1
0 2
1 2
2 2
2 1
2 0
1 0
These cells are connected to (1,1).

Is it safe to traverse a container during std::remove_if execution?

Suppose I want to remove the unique elements from an std::vector (not get rid of the duplicates, but retain only the elements that occur at least 2 times) and I want to achieve that in a pretty inefficient way - by calling std::count while std::remove_ifing. Consider the following code:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
return std::count(vec.begin(), vec.end(), n) == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
From reference on std::remove_if we know that the elements beginning from to_remove have unspecified values, but I wonder how unspecified they can really be.
To explain my concern a little further - we can see that the elements that should be removed are 1, 3, 5 and 7 - the only unique values. std::remove_if will move the 1 to the end but there is no guarantee that there will be a value 1 at the end after said operation. Can this be (due to that value being unspecified) that it will turn into 3 and make the std::count call return a count of (for example) 2 for the later encountered value 3?
Essentially my question is - is this guaranteed to work, and by work I mean to inefficiently erase unique elements from an std::vector?
I am interested in both language-lawyer answer (which could be "the standard says that this situation is possible, you should avoid it") and in-practice answer (which could be "the standard says that this situation is possible, but realistically there is no way of this value ending up as a completely differeny one, for example 3").
After the predicate returns true the first time, there will be one unspecified value in the range. That means any subsequent calls of the predicate will count an unspecified value. The count is therefore potentially incorrect, and you may either leave values unaffected that you intend to be discarded, or discard values that should be retained.
You could modify the predicate so it keeps a count of how many times it has returned true, and reduce the range accordingly. For example;
std::size_t count = 0;
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec, &count](int n)
{
bool once = (std::count(vec.begin(), vec.end() - count, n) == 1);
if (once) ++count;
return once;
});
Subtracting an integral value from a vector's end iterator is safe, but that isn't necessarily true for other containers.
You misunderstood how std::remove_if works. The to-be-removed values are not necessarily shifted to the end. See:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. cppreference
This is the only guarantee for the state of the range. According to my knowledge, it's not forbidden to shift all values around and it would still satisfy the complexity. So it might be possible that some compilers shift the unwanted values to the end but that would be just extra unnecessary work.
An example of possible implementation of removing odd numbers from 1 2 3 4 8 5:
v - read position
1 2 3 4 8 5 - X will denotes shifted from value = unspecified
^ - write position
v
1 2 3 4 8 5 1 is odd, ++read
^
v
2 X 3 4 8 5 2 is even, *write=move(*read), ++both
^
v
2 X 3 4 8 5 3 is odd, ++read
^
v
2 4 3 X 8 5 4 is even, *write=move(*read), ++both
^
v
2 4 8 X X 5 8 is even, *write=move(*read), ++both
^
2 4 8 X X 5 5 is odd, ++read
^ - this points to the new end.
So, in general, you cannot rely on count returning any meaningful values. Since in the case that move==copy (as is for ints) the resulting array is 2 4 8|4 8 5. Which has incorrect count both for the odd and even numbers. In case of std::unique_ptr the X==nullptr and thus the count for nullptr and removed values might be wrong. Other remaining values should not be left in the end part of the array as there were no copies done.
Note that the values are not unspecified as in you cannot know them. They are exactly the results of move assignments which might leave the value in unspecified state. If it specified the state of the moved-from variables ( asstd::unique_ptr does) then they would be known. E.g. if move==swap then the range will be permuted only.
I added some outputs:
#include <algorithm>
#include <iostream>
#include <vector>
#include <mutex>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
std::cout << "number " << n << ": ";
for (auto i : vec) std::cout << i << ' ';
auto c = std::count(vec.begin(), vec.end(), n);
std::cout << ", count: " << c << std::endl;
return c == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
and got
number 1: 1 2 6 3 6 2 7 4 4 5 6 , count: 1
number 2: 1 2 6 3 6 2 7 4 4 5 6 , count: 2
number 6: 2 2 6 3 6 2 7 4 4 5 6 , count: 3
number 3: 2 6 6 3 6 2 7 4 4 5 6 , count: 1
number 6: 2 6 6 3 6 2 7 4 4 5 6 , count: 4
number 2: 2 6 6 3 6 2 7 4 4 5 6 , count: 2
number 7: 2 6 6 2 6 2 7 4 4 5 6 , count: 1
number 4: 2 6 6 2 6 2 7 4 4 5 6 , count: 2
number 4: 2 6 6 2 4 2 7 4 4 5 6 , count: 3
number 5: 2 6 6 2 4 4 7 4 4 5 6 , count: 1
number 6: 2 6 6 2 4 4 7 4 4 5 6 , count: 3
2 6 6 2 4 4 6
As you can see the counts can be wrong. I'm not able to create an example for your special case but as a rule you have to worry about wrong results.
First the number 4 is counted twice and in the next step the number 4 is counted thrice. The counts are wrong and you can't rely on them.

Lower triangular of matrix in eigen

How to use eigen library to compute lower triangular of input matrix without changing columns order?
for example for matrix:
A=[1 2 3;4 5 6 ;7 8 9]
I want the result to be:
1 0 0
4 0 0
7 0 0
Your text and your example don't match. I'll go through the three possible ways I understood your question. First, we'll set up the matrix:
Matrix3d mat;
mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
If you wanted the actual lower triangular matrix, you would use:
std::cout << Matrix3d(mat.triangularView<Lower>()) << "\n\n";
or similar. The result is:
1 0 0
4 5 0
7 8 9
Note the 5,8,9 which are missing from your example. If you just wanted the left-most column, you would use:
std::cout << mat.col(0) << "\n\n";
which gives
1
4
7
If (as the second part of your example shows) you want mat * [1, 0, 0] then you could either do the matrix multiplication (not recommended) or just construct the result:
Matrix3d z = Matrix3d::Zero();
z.col(0) = mat.col(0);
std::cout << z << "\n\n";
which gives the same result as your example:
1 0 0
4 0 0
7 0 0

set_union issue while using arrays

I am trying to get union of 4 arrays using set_union. Here is the code I have so far:
int setA[5] = {2, 4, 5, 7, 8};
int setB[7] = {1, 2, 3, 4, 5, 6, 7};
int setC[5] = {2, 5, 8, 8, 15};
int setD[6] = {1, 4, 4, 6, 7, 12};
int AunionB[12];
int CunionD[11];
int finalUnion[23];
int *lastAunionB;
int *lastCunionD;
ostream_iterator<int> screen(cout, " ");
lastAunionB = set_union(setA, setA+5, setB, setB+7, AunionB);
cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;
lastCunionD = set_union(setC, setC+5, setD, setD+6, CunionD);
cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;
set_union(AunionB, AunionB+12, CunionD, CunionD+11, finalUnion);
cout << "Final Union = ";
copy(finalUnion, finalUnion+23, screen);
cout << endl;
When I ran the code, I got the following output:
AunionB = 1 2 3 4 5 6 7 8
CunionD = 1 2 4 4 5 6 7 8 8 12 15
Final Union = 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 52187240 1 1863041424 32767 0 0
Therefore, the unions of setA and setB works as intended as does the union of setC and setD. However, when I try to get the union of all for sets, it doesn't work! I'm guessing the last 5 values of finalUnion are the address fields but how do I remove them? Also, the union itself is incorrect and I can't understand why.
The size of the AunionB and Cuniond is not 12 and 11 because:
Elements from the second range that have an equivalent element in the first range are not copied to the resulting range.
Try this code:
int setA[5] = { 2, 4, 5, 7, 8 };
int setB[7] = { 1, 2, 3, 4, 5, 6, 7 };
int setC[5] = { 2, 5, 8, 8, 15 };
int setD[6] = { 1, 4, 4, 6, 7, 12 };
int AunionB[12];
int CunionD[11];
int finalUnion[23];
int *lastAunionB;
int *lastCunionD;
ostream_iterator<int> screen(cout, " ");
lastAunionB = set_union(setA, setA + 5, setB, setB + 7, AunionB);
cout << "AunionB = ";
copy(AunionB, lastAunionB, screen);
cout << endl;
lastCunionD = set_union(setC, setC + 5, setD, setD + 6, CunionD);
cout << "CunionD = ";
copy(CunionD, lastCunionD, screen);
cout << endl;
int *finalUnionEnd;
finalUnionEnd = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);
cout << "Final Union = ";
copy(finalUnion, finalUnionEnd, screen);
cout << endl;
And then you got the right result:
Final Union = 1 2 3 4 4 5 6 7 8 8 12 15
A Union operation removes values that the two sets have in common.
Note that AUnionB has 8 elements (not the 12 that your code predicts).
You need to adjust your union-of-union code to account for the actual size of the two initial unions. You have everything prepared to do it correctly:
int *lastFinalUnion = set_union(AunionB, lastAunionB, CunionD, lastCunionD, finalUnion);
Note that set C has two distinct occurrences of 8 and set D has two distinct occurrences of 4, which is why they appear duplicated in the intermediate result.
UPDATE
Also, I tried your code and i'm getting the answer as 1 2 3 4 5 6 7 2 4 4 5 6 7 8 8 12 15 . Shouldn't the answer be 1 2 3 4 4 5 6 7 8 8 12 15
I believe you are correct, but I'm not in front of a C++ compiler to step through and see what's doing on, or to verify your output. The actual code was edited in by another SO member, but it looks correct to me.
In the simplest case, set_union performs the "union" operation from set theory: the output range contains a copy of every element that is contained in [first1, last1), [first2, last2), or both. The general case is more complicated, because the input ranges may contain duplicate elements. The generalization is that if a value appears m times in [first1, last1) and n times in [first2, last2) (where m or n may be zero), then it appears max(m,n) times in the output range.
https://www.sgi.com/tech/stl/set_union.html

C++ negative array indices

I want to loop an array then during each loop I want to loop backwards over the previous 5 elements.
So given this array
int arr[24]={3, 1, 4, 1, 7, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4}
and this nested loop
for(int i=0;i<arr.size;i++)
{
for(int h=i-5; h<i; h++)
{
//things happen
}
}
So, if i=0, second loop would loop last few elements 4,6,2,6,5.
How could you handle this?
I'm assuming that:
You only want to go over previous values (i.e. no wrap around) You
You don't actually want arr to be a multi-dimensional array as suggested
by your choice of tags
You want to include the current i in your five values
This is just a small modification to your code that will do (what I think) you are asking:
#include <math>
int main()
{
int arr[24]={3, 1, 4, 1, 7, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4}
for(int i=0;i<arr.size;i++)
{
for(int h = max(i-4, 0); h < i+1; h++)
{
//things happen
}
}
}
note the h = max(i-4, 0) and h < i+1This will reduce the number of iterations of the inner loop so that it starts from index 0 and loops up through the five values up to and including i. (four values and i). h will always be within bounds.
The case where i==arr.size won't be a problem in the inner loop as the outer loop will terminate before that happens (i is always within bounds).
Edit: I saw this comment:
I want the first element to consider the last final 5 elements of the array though.
in which case, your loops should look like:
for(int i=0;i<arr.size;i++)
{
for(int h=0; h<5; h++)
{
int index = (i + arr.size - h) % arr.size;
//things happen
//access array with arr[index];
}
}
This should do what you want:
When i=0, h=0 index=(0+24-0)%24 which is 0. For h=1 we go one less, index=(0+24-1)%24 = 23 and so on for the next values of h.
The code gets the last 5 values, wrapping round, inclusive of the current value. (so will get 20,21,22,23,0 when i=0, 21,22,23,0,1 when i=1)
If you want the five before, non-inclusive, then inner loop should be:
for(int h=1; h<=5; h++)
here is the current output of the loop as it stands:
i 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 ... 22 22 22 22 22 23 23 23 23 23
h 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 ... 0 1 2 3 4 0 1 2 3 4
index 0 23 22 21 20 1 0 23 22 21 2 1 0 23 22 3 2 1 0 23 ... 22 21 20 19 18 23 22 21 20 19
I assume you want it to loop around (don't know why). if so, use modulo:
int index = (h + arr.size) % arr.size;
Using the modulo operator.
for (int i = 0; i < arr.size; i++)
{
for (int h = 5; h > 0; h--)
{
const int array_length = sizeof(arr) / sizeof(arr[0]);
int index = (i - h + array_length) % array_length; // Use 'sizeof(arr) / sizeof(arr[0])' to get the size of the array
//things happen
}
}
Is using if statement not an option?
const int array_size = 24;
int arr[array_size] = { 1,3,4,5,...,2 }
for(int i=0;i<array_size;i++)
{
for(int h=i-5; h<i; h++)
{
int arr_index = (h >= 0) ? h : (array_size + h);
//do your things with arr[arr_index]
}
}
you may also start the nested loop with something like:
for(int h=i-min(i,5);h<i;++h)
{
}
which let you process first 5 cells as well. also, if you are dealing with some kind of signal or image processing consider extending arr to have 29 elements with preceding 5 zeros or whatever value would be suitable, and start the first for-loop with 5th element.
Just make an if statement in nested loop. Something like this
for( int h = i-5; h < i; h++ )
{
// do stuff
if( i == 0 )
break;
}