finding the common elements of vectors which are inside another map - c++

dear all,
i have a map, defined as map<int, vector<int> > my_map. So, for example it looks like as follows,
my_map=
0 1 2 6 5 4
1 0 2 3 4 5
2 0 1 4
3 1
4 1 2 0 7 5 6
5 1 0 6 4
6 0 5 4
7 4
vector<int> element_common(map<int, vector<int> > &my_map, int s1, int s2){
vector<int> common2;
vector<int> first_vector=my_map[s1];
vector<int>::iterator snd_vector_begin= my_map[s2].begin();
vector<int>::iterator snd_vector_end= my_map[s2].end();
for (vector<int>::iterator any=first_vector.begin();
any!=first_vector.end();
any++){
// check if any is in other_list
vector<int>::iterator any_in_snd_vector_iterator= find (snd_vector_begin,snd_vector_end, *any);
if(any_in_snd_vector_iterator==snd_vector_end){
common2.push_back(*any);
}
}
return common2;
i wrote a function above function to get common elements from the vector parts which are relevant to 2 given keys. when keys are equal to s1 and s2, i.e. s1=1 and s2=4. then my function should give me 0,2,5. but i got 3,4. please help me to rectify my function.

If you can guarantee your vectors are sorted then you can improve your performance substantially from O(mn) to O(m + n):
std::vector<int> common;
std::set_intersection(vec1.begin(), vec1.end(),
vec2.begin(), vec2.end(),
std::back_inserter(common));

You got the test exactly backwards:
if(any_in_2nd_vector_iterator==2nd_vector_end){
is true when the element ISN'T FOUND in the second vector. Try !=.
Then, you can avoid needless copying of vectors by using a reference:
const vector<int>& first_vector=my_map[s1];
and if your vectors get much larger, it may be faster to do a hash lookup (or pre-sorted merge if the vectors are always kept sorted) instead of a call to find which has to check every element.

Related

What is nth_element and what does it do exactly? and how to implement it

I've almost understood many STL algorithms until I've reached the algorithm std::nth_element. I 'm stuck on it; I don't know how it works and it does do exactly.
For education and understanding sake can someone explain to me how the algorithm std::nth_element works?
std::vector<int> v{ 9, 3, 6, 2, 1, 7, 8, 5, 4, 0 };
std::nth_element(v.begin(), v.begin() + 2, v.end());
for (auto i : v)
std::cout << i << " ";
std::cout << '\n';
The output:
1 0 2 3 6 7 8 5 4 9
So where is nth element here?
How and what the algorithm does?
Does it do some sort of partial sorting?
Here is some explanation from cppreference.com:
nth_element is a partial sorting algorithm that rearranges elements in [first, last) such that:
The element pointed at by nth is changed to whatever element would occur in that position if [first, last) was sorted.
All of the elements before this new nth element are less than or equal to the elements after the new nth element.
More formally, nth_element partially sorts the range [first, last) in ascending order so that the condition !(*j < *i) (for the first version, or comp(*j, *i) == false for the second version) is met for any i in the range [first, nth) and for any j in the range [nth, last). The element placed in the nth position is exactly the element that would occur in this position if the range was fully sorted.
nth may be the end iterator, in this case the function has no effect.
I am still confused about it. What is nth element and how to implement a possible algorithm like that?. For education sake I've mimicked many STL algorithms. Thank you so much!
So where is nth element here?
The n-th element is the 2 at index 2 because thats what you asked for when you passed begin()+2.
The element pointed at by nth is changed to whatever element would occur in that position if [first, last) was sorted.
This means that, if the vector was sorted, the order of elements would be
0 1 2 3 4 5 6 7 8 9
^--- begin() + 2
You asked to have 3rd largest element at index 2 (3rd position), and thats what the algorithm does.
In addition it puts all elements smaller in the front and all elements larger in the back:
!(*j < *i) (for the first version, or comp(*j, *i) == false for the second version) is met for any i in the range [first, nth) and for any j in the range [nth, last).
Let's use indices rather than iterators, then for any i < 2 and any j > 2 it holds that v[i] < v[j]. In other words, 1 and 0 are both smaller than any element in 2 3 6 7 8 5 4 9.
I will explain my code first before getting into your problem
for example I have code like this
int m_array_biasa[8] {3,2,10,45,33,56,23,47};
and I use it normally like
std::nth_element(m_array_biasa, m_array_biasa + 4, m_array_biasa + 8);
so nth element in here is 4[33], the rule of std::nth_element is that the number on the left of nth must be less than or equal to and the number on the right must be greater than nth
and don't forget, data must be sorted from small to large (default)
so the data that was originally
3,2,10,45,33,56,23,47
changed to
2 3 10 23 33 45 47 56
my nth is 4[33], so the above rules apply (without including the sorting result)
and the result is
3 2 10 23 33 56 45 47
note above, position 33 has not changed, but sometimes it's a bit confusing, for example we change 33 to 1, then the result
2 1 3 10 23 45 47 56
what happened here, why did the number 1 move (replaced by 23), why didn't it stay like the previous number 33, I said before that we have to sort the data first (see sorting above), it turns out that index nth[4] is number 23 , then the number 1 is replaced with the number 23, why should it be replaced?, see the nth_element rule
now on to your question.
std::vector<int> v{ 9, 3, 6, 2, 1, 7, 8, 5, 4, 0 };
std::nth_element(v.begin(), v.begin() + 2, v.end());
v.begin() contains 9, v.begin() + 2 contains 6, remember, nth_element will sort it first
0 1 2 3 4 5 6 7 8 9
and your output is
1 0 2 3 6 7 8 5 4 9
the nth[2] above (acccording your v.begin() + 2)p is 2, so 2 here is like a reference for other data, the data before 2 must be less than it, and after it must be more than it

How can I sort a map according to a property of its values?

I've created a map having a vector as below:
map<int,vector<int>> mymap;
How can I sort this map according to the nth value of the vector contained by map?
You can't. You can provide a custom comparator to make the underlying data get sorted another way than the default, but this only relates to keys, not values. If you have a requirement for your container's elements to exist in some specific, value-defined order, then you're using the wrong container.
You can switch to a set, and take advantage of the fact that there is no distinction there between "key" and "value", and hack the underlying sorting yourself:
template <std::size_t N>
struct MyComparator
{
typedef std::pair<int, std::vector<int>> value_type;
bool operator()(const value_type& lhs, const value_type& rhs)
{
return lhs.second.at(N) < rhs.second.at(N);
}
};
/**
* A set of (int, int{2,}) pairs, sorted by the 2nd element in
* the 2nd item of each pair.
*/
std::set<std::pair<int, std::vector<int>>, MyComparator<1>> my_data;
int main()
{
my_data.insert(std::make_pair(1, std::vector<int>{0,5,0,0}));
my_data.insert(std::make_pair(2, std::vector<int>{0,2,0,0}));
my_data.insert(std::make_pair(3, std::vector<int>{0,1,0,0}));
my_data.insert(std::make_pair(4, std::vector<int>{0,9,0,0}));
for (const auto& el : my_data)
std::cout << el.first << ' ';
}
// Output: 3 2 1 4
(live demo)
However, if you still need to perform lookup on key as well, then you're really in trouble and need to rethink some things. You may need to duplicate your data or provide an indexing vector.
map<int,vector<int>> mymap;
How can i sort this map according to the nth value of the vector contained by map?
That's only possible if you're prepared to use that nth value as the integer key too, as in consistently assigning:
mymap[v[n - 1]] = v;
If you're doing that, you might consider a set<vector<int>>, which removes the redundant storage of that "key" element - you would then need to provide a custom comparison though....
If you envisage taking an existing populated map that doesn't have that ordering, then sorting its elements - that's totally impossible. You'll have to copy the elements out to another container, such as a set that's ordered on the nth element, or a vector that you std::sort after populating.
If I have understood correctly you can (build) add elements to the map the following way
std::vector<int> v = { 1, 2, 3 };
std::vector<int>::size_type n = 2;
mymap[v[n]] = v;
Here is an example
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <cstdlib>
#include <ctime>
int main()
{
std::srand( ( unsigned )time( 0 ) );
const size_t N = 10;
std::map<int, std::vector<int>> m;
for ( size_t i = 0; i < N; i++ )
{
std::vector<int> v( N );
std::generate( v.begin(), v.end(), []{ return std::rand() % N; } );
m[v[0]] = v;
}
for ( auto &p : m )
{
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
0 1 7 8 1 2 9 0 0 9
1 6 3 1 3 5 0 3 1 5
3 8 0 0 0 7 1 2 9 7
5 9 5 0 7 1 2 0 6 3
6 4 7 5 4 0 0 4 2 0
7 9 8 6 5 5 9 9 4 5
8 3 8 0 5 9 6 6 8 3
9 5 4 7 4 0 3 5 1 9
Take into account that as there can be duplicated vectors (that is that have the same value of the n-th element (in my example n is equal to 0) then some vectors will not be added to the map. If you want to have duplicates then you should use for example std::multimap
Also you can build a new map according to the criteria based on an existent map.
You can abuse the fact a c++ map uses a tree sorted by its keys. This means that you can either create a new map, with as keys the values you wish it to be sorted on, but you can also create a vector with references to the items in your map, and sort that vector (or the other way around: you could have a sorted vector, and use a map to create an index on your vector). Be sure to use a multimap in the case of duplicate keys.

finding an element in a 2d vector and then removing it

Let's say I have my data in a 4 by 3 vector<vector<int> > as:
1 2 3
4 5 6
7 8 9
10 11 12
and I want to delete every row containing the element 8 and end up like:
1 2 3
4 5 6
10 11 12
I have been trying to do:
for (vector<vector<int> >::iterator it = v.begin(); it != v.end(); it++) {
if (find(it->begin(), it->end(), 8)) {
// I will remove the row in here
}
}
which gives me:
error: no matching function for call to 'find(std::vector<int>::iterator, std::vector<int>::iterator, int)'
I don't have much experience with stl so I was wondering:
what's wrong with my find call?
is it safe to remove an element from a vector while iterating over it?
Ofc any elegant solution to my problem is also welcomed..
what's wrong with my find call?
You probably forgot to #include <algorithm>
is it safe to remove an element from a vector while iterating over it?
Look into the erase-remove idiom - erasing vector elements can be tricky.

how to sort a triple in C++?

I want to know how to sort the triple below based on the first column using C++?
Can I use std::map?
0 0 1
1 2 0
2 0 3
0 1 4
the wanted result is
0 0 1
0 1 4
1 2 0
2 0 3
You could just use std::sort on, for example, a vector of std::tuple - the default comparison is lexicographic, so first column counts most.
Assuming you are sorting a std::vector<std::vector<int>>
C++11:
std::sort(begin(vec), end(vec), [](const std::vector<int>& a,
const std::vector<int>& b){
return a[0] < b[0]; // sorting on the first column only
});
Assuming you want lexical order:
std::sort(begin(vec), end(vec));

std::next_permutation missing one entry

Following program is missing one permutation entry.
#include <iostream>
#include <vector>
#include <algorithm>
int main ( int argc, char **argv) {
std::vector<int> temp;
temp.push_back(10);
temp.push_back(2);
temp.push_back(4);
temp.push_back(4);
do {
std::copy(temp.begin(),temp.end(),std::ostream_iterator<int>(std::cout," "));
std::cout << std::endl;
}while ( std::next_permutation (temp.begin(), temp.end()));
}
Following is the output of the program
10 2 4 4
10 4 2 4
10 4 4 2
why it is missing one entry which is
2 4 4 10
This is because that permutation is the first ordering for the list of number that you have.
You would need to sort the original array, then this permutation will be listed as the very first one.
std::vector<int> temp;
temp.push_back(10);
temp.push_back(2);
temp.push_back(4);
temp.push_back(4);
std::sort(temp.begin(),temp.end() );
Alternatively, you could just push the elements in sorted order, but for practical purposes, you should always sort if you want to generate all possible permutations.
It's actually missing a few other valid permutations: 2 10 4 4 and 2 4 10 4, and 4 4 10 2 for example.
As to why they are missing: it says, right there in the documentation:
Return value
true if the function could rearrange the object as a lexicographically greater permutation. Otherwise, the function returns false to indicate that the arrangement is not greater than the previous, but the lowest possible (sorted in ascending order).
So the while loop ends after 10 4 4 2, because that is the lexicographically greatest permutation (the one that's "biggest" when you compare them left-to-right, i.e. the one that's in descending order). After printing that one, next_permutation fails to get to the 'next' permutation, and wraps around to the "beginning" permutation of 2 4 4 10; but that is not printed because the function also returned false.