Insert with pair vector - c++

Is is possible to use the insert function for a vector but make a pair just like we can do with push_back?
void insert(std::vector<int, std::string>& cont, int value)
{
std::vector<int>::iterator it = std::lower_bound(
cont.begin(),
cont.end(),
value,
std::less<int>()
); // find proper position in descending order
cont.insert((it, std::make_pair(value,""))); // insert before iterator it
}

std::vector<int,std::string> is not allowed, you could change this to std::vector<std::pair<int,std::string>>
furthermore
std::vector<int>::iterator it = std::lower_bound(cont.begin(), cont.end(), value, std::less<int>());
should be changed to compare pairs and return std::vector<std::pair<int,std::string>>::iterator

The function can be written the foollowing way
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <string>
std::vector<std::pair<int, std::string>>::iterator
insert( std::vector<std::pair<int, std::string>> &v, int value, bool before = true )
{
std::vector<std::pair<int, std::string>>::iterator it;
std::pair<int, std::string> pair( value, "" );
if ( before )
{
it = std::lower_bound( v.begin(), v.end(), pair );
}
else
{
it = std::upper_bound( v.begin(), v.end(), pair );
}
return v.insert( it, pair );
}
int main()
{
std::vector<std::pair<int, std::string>> v { { 1, "A" }, { 2, "B" } };
for ( const auto &p : v )
{
std::cout << p.first << " \"" << p.second << "\"" << std::endl;
}
std::cout << std::endl;
insert( v, 1 );
insert( v, 1, false );
insert( v, 2 );
insert( v, 2, false );
for ( const auto &p : v )
{
std::cout << p.first << " \"" << p.second << "\"" << std::endl;
}
std::cout << std::endl;
return 0;
}
The program output is
1 "A"
2 "B"
1 ""
1 ""
1 "A"
2 ""
2 ""
2 "B"
As for me I would declare the function the following way
std::vector<std::pair<int, std::string>>::iterator
insert( std::vector<std::pair<int, std::string>> &v,
const std::vector<std::pair<int, std::string>>::value_type &value,
bool before = true );

Related

How to sort array of pair <int, pair <int, int> >, by first element, but descending order?

I want to sort an array containing pair <int, pair <int, int> >, by the first value, in descending order.
I had
pair <int, pair<int, int> > adj[10];
which had values in it, unsorted.
When I used
sort(adj, adj + 10);
it would sort the array based on the adj[i].first value, in ascending order.
However, when I tried sorting in descending order
sort(adj, adj + 10, greater<int>());
It wasn't letting me.
Is there other way to sort by descending order?
You could write:
std::sort(std::begin(adj), std::end(adj),
std::greater<std::pair<int, std::pair<int, int>>>{});
In c++14, you could simplify this to:
std::sort(std::begin(adj), std::end(adj), std::greater<>{});
In c++17, you could simply it a little more:
std::sort(std::begin(adj), std::end(adj), std::greater{});
In c++20, you could simplify this much further:
std::ranges::sort(adj, std::greater{});
You can write a custom predicate using a lambda.
std::sort(std::begin(adj),
std::end(adj),
[](auto const& lhs, auto const& rhs)
{
return lhs.first > rhs.first;
});
Note that the above predicate only considers the first element. You could expand that to look at the further elements if you wanted more complex sorting.
A simple way is to use a lambda expression as for example
#include <utility>
#include <iterator>
#include <algorithm>
//...
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 1, 2 } } { 1, { 2, 1 } }
As you can see from the output if two elements of the array have equal values of the first member of an object of the type std::pair then values of the second member are not taken into account and can be unordered.
Another approach is to use the expression std::gretar<>(). That is to use the default template argument for the functional object std::greater. Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ), std::greater<>() );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 2, 1 } } { 1, { 1, 2 } }
In this case if two elements have an equal value of the first member then they are ordered according to values of the second member.
If your compiler does not support the C++ 14 Standard then the same effect of using std::greater<> you can achieve using the following lambda expression.
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b < a;
} );
since you are using c++14 here is how: sort using std::greater<>{}
std::pair <int, std::pair<int, int> > adj[3];
adj[0]=std::make_pair(10,std::make_pair(0,0));
adj[1]=std::make_pair(1,std::make_pair(0,0));
adj[2]=std::make_pair(7,std::make_pair(0,0));
std::sort(adj, adj+3, std::greater<>{});
std::cout << "Sorted \n";
for (auto x=0; x<3;++x)
std::cout << "x: " << adj[x].first << "\n";
return 0;

How do I get the first layer index of 2D vector?

I need help getting the first layer index of a 2D vector. Each element is unique, so there are no repetitions of element. Here's what I mean bellow.
I have a vector defined as:
vector<vector<int>> vec { {0,1} ,
{2} ,
{3,4},
{5,6} }
Then, I want to get the index of where any of the numbers is, on the "first" layer.
By this, I mean if I say
index of 4, it should return 2.
If I say, index of 6, it should return 3.
Thank you in advance!
You can use std::find and std::find_if:
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
std::vector<std::vector<int>> vec { {0,1} ,
{2} ,
{3,4},
{5,6} };
// Search for the 4
auto iter = std::find_if(vec.begin(), vec.end(), [](const std::vector<int>& v)
{return std::find(v.begin(), v.end(), 4) != v.end();});
// Output the distance between the item and the beginning of the vector
std::cout << std::distance(vec.begin(), iter);
}
Output:
2
The outer std::find_if searches the std::vector<vector<int>> and the argument to the lambda will be a reference to each inner vector. The inner std::find searches that inner vector for the value.
You could write a function that calculates the index like:
int findIndex(const std::vector<std::vector<int>> &vec, int val)
{
auto it = std::find_if(vec.cbegin(), vec.cend(), [val](const std::vector<int> &v) {
return std::find(v.cbegin(), v.cend(), val) != v.cend();
});
return it != vec.cend() ? std::distance(vec.cbegin(), it) : -1;
}
You can use the standard algorithm std::find_if along with the algorithm std::find.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<std::vector<int>> v =
{
{ 0, 1 }, { 2 }, { 3, 4 }, { 5, 6 }
};
auto present = []( const auto &v, const auto &value )
{
return std::find( std::begin( v ), std::end( v ), value ) != std::end( v );
};
int value = 4;
size_t i = std::distance( std::begin( v ),
std::find_if( std::begin( v ), std::end( v ),
[&, present, value]( const auto &item )
{
return present( item, value );
} ) );
if ( i != v.size() ) std::cout << value << ": " << i << '\n';
value = 6;
i = std::distance( std::begin( v ),
std::find_if( std::begin( v ), std::end( v ),
[&, present, value]( const auto &item )
{
return present( item, value );
} ) );
if ( i != v.size() ) std::cout << value << ": " << i << '\n';
return 0;
}
The program output is
4: 2
6: 3
You can use a hash-table data structure like unordered_map to do this in O(1) time.
unordered_map <int,int> m;
for(int i=0;i<vec.size();i++){
for(int j=0;j<vec[i].size();j++){
m[vec[i][j]] = i;
}
}

How to get lower_bound for map in a specific range?

I want to find the lower_bound for my target in a map(in a range).
I have known another solution:
int main() {
map<int,int> m;
auto it=m.lower_bound(10);
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
BUT, I want to how to use std::lower_bound(m.begin(),m.end(),***).
int main() {
map<int,int> m;
auto it=std::lower_bound(m.begin(),m.end(),10);
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
main.cpp:29:43: required from here
/usr/local/Cellar/gcc/7.3.0_1/include/c++/7.3.0/bits/predefined_ops.h:65:22: error: no match for 'operator<' (operand types are 'std::pair' and 'const int')
{ return *__it < __val; }
The value_type of a map is std::pair<const Key,Value>, so you'll need to supply such a pair as argument.
Given that you are interested only in the key part, it's better to use the overload of std::lower_bound() that accepts a function object:
auto const it = std::lower_bound(m.begin(), m.end(), std::make_pair(10, 0),
[](auto const& a, auto const& b){ return a.first < b.first; });
I believe, from reading the docs, but haven't confirmed, that we can use the map's comparer:
auto const it = std::lower_bound(m.begin(), m.end(), std::make_pair(10, 0),
m.value_comp());
It seems you mean the following
#include <iostream>
#include <map>
#include <iterator>
#include <algorithm>
int main()
{
std::map<int, int> m =
{
{ 2, 1 }, { 4, 2 }, { 6, 3 }, { 8, 4 }, { 10, -1 }, { 10, 0 }, { 12, 2 }
};
int key = 10;
auto it = m.lower_bound( key );
std::cout << "{ " << it->first << ", " << it->second << " }\n";
it = std::lower_bound( std::begin( m ), std::end( m ), key,
[&]( const auto &p, const auto &value ) { return p.first < value; } );
std::cout << "{ " << it->first << ", " << it->second << " }\n";
return 0;
}
The program output is
{ 10, -1 }
{ 10, -1 }
That is in the standard algorithm std::lower_bound you can use a lambda expression.

C++ How to create a map from two other maps

How to create map MyMap3 as:
std::map< vector<std::pair<int, int>>, int > MyMap3
Example:
MyMap3[0] = ((1,3) , (1,5), 7 ) // 5 = 4 + 3
MyMap3[1] = ( (2,1) , (2,4), 6 ) // 6 = 1 + 5
Where the key = (vector of pairs) extract from 'MyMap1',
and the value = the sum of the pairs' values in 'MyMap2'.
I also don't care about the pair order, (2,4) is the same as (4,2)
std::map <int, vector<pair<int, int>> > MyMap1;
std::map< std::pair< int, int>, int> MyMap2;
Here is an Example:
MyMap1[0] = (0, (1,3) , (1,5) )
MyMap1[1] = (1, (2,1) , (2,4) )
MyMap2[0] = ( (1,3) , 4 )
MyMap2[1] = ( (1,5) , 3 )
MyMap2[2] = ( (2,1) , 1 )
MyMap2[3] = ( (4,2) , 5 )
I don't know how to do that, and this is my try:
std::map <int, vector<pair<int, int>> > ::iterator it1 = MyMap1.begin();
std::map<std::pair< int, int>, int> ::iterator it2 = MyMap2.begin();
// std::map< vector<pair<int, int> >, int> MyMap3;
std::map< pair<int, int> , int> MyMap3;
int i = 0;
while (it1 != MyMap1.end())
{
vector< pair<int, int> > temp = MyMap1[i];
vector< pair<int, int> > ::iterator it3 = temp.begin();
while (it3 != temp.end())
{
int a = it2->first.first;
int b = it2->first.second;
while (it2 != MyMap2.end())
{
if (it3 == MyMap2.find(std::make_pair(a, b))
MyMap3[std::make_pair(a, b)] += it2->second;
else
++it2;
}
++it3;
++i;
}
++it1;
}
I have syntax error in:
if (it3 == MyMap2.find(make_pair(a, b)))
MyMap3[std::make_pair(a, b)] += it2->second;
Your question is confuse, i decipher you want for each key in map1 to sum the value of each pair in the vector found in the map2 to a single value, and store the result with the map1 key. Not really what your code do…
Example result : http://coliru.stacked-crooked.com/a/a4d77c77fa6896c1
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <utility>
using Map1 = std::map< int, std::vector<std::pair<int,int>>>;
using Map2 = std::map< std::pair<int,int>, int >;
using Map3 = std::map< int, int >;
Map3 foo( Map1 const & m1, Map2 const & m2 ) {
auto m2end = m2.end(); // a constant call is move outside the loop
Map3 result;
for( auto & v1 : m1 ) { // each entry in m1 is made of the key as first and the value as second
for( auto & p1 : v1.second ) { // iterate over the vector of pair
auto v2it = m2.find( p1 ); // search for the pair
if ( v2it != m2end ) {
result[v1.first] += v2it->second; // if the pair was found, add the value for it to the result, using the map1 key as key
}
}
}
return result;
}
template<typename T,typename S>
std::ostream& operator<<(std::ostream& os, const std::pair<T,S>& pair )
{
os << "{ " << pair.first << ", " << pair.second << " }";
return os;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec)
{
os << "( ";
for (auto& el : vec)
{
os << el << ", ";
}
os << " )";
return os;
}
template<typename T,typename S>
std::ostream& operator<<(std::ostream& os, const std::map<T,S>& map)
{
for (auto& el : map)
{
os << el.first << " : " << el.second << "\n";
}
return os;
}
int main()
{
Map1 m1 { { 0, { {1,3}, {1,5}} }, { 1, { {2,1}, {2,4}} }, };
Map2 m2 { { {1,3}, 4 }, { {1,5}, 3 }, { {2,1}, 1 }, { {2,4}, 5 }, };
auto m3 = foo( m1, m2);
std::cout << "m1 :\n" << m1 << std::endl;
std::cout << "m2 :\n" << m2 << std::endl;
std::cout << "m3 :\n" << m3 << std::endl;
}

Merge two maps, summing values for same keys in C++

I have two std::map<int,int> maps and wish to merge them into a third map like this:
if the same key is found in both maps, create a pair in the third map with the same key and a value which a sum of values from the first and second map, otherwise just copy a pair to the third map.
I suspect it can be done with std::accumulate, but I don't understand it well enough.
Here is an example how to do the task with using std::accumulate
#include <iostream>
#include <map>
#include <numeric>
int main()
{
std::map<int, int> m1 = { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 4, 4 } };
std::map<int, int> m2 = { { 2, 5 }, { 3, 1 }, { 5, 5 } };
for ( const auto &p : m1 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
for ( const auto &p : m2 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
std::map<int, int> m3 = std::accumulate( m1.begin(), m1.end(), std::map<int, int>(),
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
for ( const auto &p : m3 )
{
std::cout << "{ " << p.first << ", " << p.second << " } ";
}
std::cout << std::endl;
return 0;
}
The output is
{ 1, 1 } { 2, 2 } { 3, 3 } { 4, 4 }
{ 2, 5 } { 3, 1 } { 5, 5 }
{ 1, 1 } { 2, 7 } { 3, 4 } { 4, 4 } { 5, 5 }
In fact only for the second map there is a need to use std::accumulate. The first map can be simply copied or assigned to m3.
For example
std::map<int, int> m3 = m1;
m3 = std::accumulate( m2.begin(), m2.end(), m3,
[]( std::map<int, int> &m, const std::pair<const int, int> &p )
{
return ( m[p.first] +=p.second, m );
} );
An overly generic solution inspired by std::set_union. Unlike the first suggested answer, this should run in O(n) instead of O(n log n).
Edit: it's still O(n log n) because of insertions into the final map.
#include <map>
#include <iostream>
#include <iterator>
#include <algorithm>
template<class InputIterT1, class InputIterT2, class OutputIterT, class Comparator, class Func>
OutputIterT merge_apply(
InputIterT1 first1, InputIterT1 last1,
InputIterT2 first2, InputIterT2 last2,
OutputIterT result, Comparator comp, Func func) {
while (true)
{
if (first1 == last1) return std::copy(first2, last2, result);
if (first2 == last2) return std::copy(first1, last1, result);
if (comp(*first1, *first2) < 0) {
*result = *first1;
++first1;
} else if (comp(*first1, *first2) > 0) {
*result = *first2;
++first2;
} else {
*result = func(*first1, *first2);
++first1;
++first2;
}
++result;
}
}
template<class T>
int compare_first(T a, T b) {
return a.first - b.first;
}
template<class T>
T sum_pairs(T a, T b) {
return std::make_pair(a.first, a.second + b.second);
}
using namespace std;
int main(int argc, char **argv) {
map<int,int> a,b,c;
a[1] = 10;
a[2] = 11;
b[2] = 100;
b[3] = 101;
merge_apply(a.begin(), a.end(), b.begin(), b.end(), inserter(c, c.begin()),
compare_first<pair<int, int> >, sum_pairs<pair<int, int> >);
for (auto item : c)
cout << item.first << " " << item.second << endl;
}
I don't think it will be easy (if not impossible) to find a suitable std::algorithm that serves the purpose.
The easiest way would be to first make a copy of map1 to map_result.
Then iterate through map2 and see if any key already exists in map_result then add the values, else add the key_value pair to map_result.
std::map<int,int> map_result( map1 );
for (auto it=map2.begin(); it!=map2.end(); ++it) {
if ( map_result[it->first] )
map_result[it->first] += it->second;
else
map_result[it->first] = it->second;
}