std::map<int, std::vector<int>> tmp_map = { { 1, [10,5,4] }, { 2, [5,5,1] },
{ 3, [2,4,3] }, { 4, [9,7,8] } };
I want to order this map by the 3rd value in vector value.
So the outcome will be like :
{ { 2, [5,5,1] },{ 3, [2,4,3] },{ 1, [10,5,4] },{ 4, [9,7,8] } }
Standard approach . . .
Copy map to vector
Sort vector with custom comparator
#include <iostream>
#include <map>
#include <vector>
#include <utility>
#include <algorithm>
int main() {
std::map<int, std::vector<int>> tmp_map = { { 1,{10,5,4} }, { 2,{5,5,1} },
{ 3,{2,4,3} }, { 4,{9,7,8} } };
// For easier and shorter writing
using DataType = std::pair<int, std::vector<int>>;
// Create Vector with Elements from Map
std::vector<DataType> data(tmp_map.begin(), tmp_map.end());
// Sort data
std::sort(data.begin(), data.end(), [](const DataType& d1, const DataType& d2) { return d1.second[2] < d2.second[2]; });
// show result
for (const auto& [key, value] : data) {
std::cout << key << " --> ";
for (const int i : value) std::cout << i << " ";
std::cout << "\n";
}
return 0;
}
You're map is already sorted by its key value so you cannot reorder it inplace. What you should do instead is copy it into a vector and then sort it using a custom operator like this:
#include <map>
#include <vector>
#include <algorithm>
int main()
{
std::map<int, std::vector<int>> tmp_map = { { 1, {10,5,4} }, { 2, {5,5,1} },
{ 3, {2,4,3} }, { 4, {9,7,8} } };
//! Copy the map
using P = std::pair<int, std::vector<int>>;
std::vector<P> copy(tmp_map.begin(), tmp_map.end());
//! Sort it the way you want (here I'm sorting on based on the second element
//! of the array.
std::sort(copy.begin(), copy.end(), [](const P& a, const P& b)
{
return a.second[2] < b.second[2];
});
}
Related
I have a data struct -
{"BRAZIL", { {"IPHONE",{100,100} },{"IPOD", {65,100} } }
I want to use operator = to save the data into a struct . I tried to design the struct like map<string, vector<map<string, vector<int>>>>,and use -
price_stock["BRAZIL"] = { { "IPHONE", { 100, 100 } }, { "IPOD", { 65, 100 } } }
But I failed to directly assign the data into struct.
You are missing a level of braces:
price_stock["BRAZIL"] = {
{ // first element in vector
{"IPHONE", {100, 100}} // element in inner map
},
{ // second element in vector
{"IPOD", {65, 100}} // element in inner map
}
};
Below I have given a simple example on how to use a struct in C++.
#include <iostream>
#include <string>
#include <map>
#include <vector>
struct prices {
std::string title;
int stock;
int price;
};
int main ()
{
std::map<std::string, std::vector<prices> > priceMap;
std::vector<prices> priceVec {{"IPHONE",100,100}, {"IPOD",65,100}};
priceMap["Brazil"] = priceVec;
for (auto& itemVector : priceMap) {
for (auto& structItem : itemVector.second) {
std::cout << structItem.title << ":" << structItem.price << std::endl;
}
}
}
I use boost::geometry::model::box in a class like this:
struct Feature {
typedef boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian> point;
typedef boost::geometry::model::box<point> box;
box bounds;
//... other members ...
};
std::list<Feature> v;
and I want to remove duplicates in v.
Normally I'd write a sort predicate so that I can do this:
v.sort(sort_pred); //?
std::unique(v.begin(), v.end());
I'm able to use boost::geometry::equals (as described in How do I compare Boost Geometries?) to write operator==, so std::unique works. Is there a similar function I can use to write the predicate to sort, or do I need to write one from scratch?
Alternatively, is there a better way in boost::geometry to remove duplicates?
I think you can't re-use anything from boost::geometry::index as (sadly) the results of even a nearest() query is not ordered.
So, here you go with my ... simplest take on it:
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/io/io.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
// #include <boost/range/adaptors.hpp>
#include <tuple>
#include <iostream>
#include <iomanip>
namespace bg = boost::geometry;
namespace bgm = bg::model;
typedef bgm::point<double, 2, bg::cs::cartesian> point;
typedef bgm::box<point> box;
namespace std {
// less
template <> struct less<point> {
bool operator()(point const& a, point const& b) const { return std::tie(a.get<0>(), a.get<1>()) < std::tie(b.get<0>(), b.get<1>()); }
};
template <> struct less<box> {
bool operator()(box const& a, box const& b) const { return
std::tie(a.min_corner().get<0>(), a.min_corner().get<1>(), a.max_corner().get<0>(), a.max_corner().get<1>())
< std::tie(b.min_corner().get<0>(), b.min_corner().get<1>(), b.max_corner().get<0>(), b.max_corner().get<1>()); }
};
// equal_to
template <> struct equal_to<point> {
bool operator()(point const& a, point const& b) const { return std::tie(a.get<0>(), a.get<1>()) == std::tie(b.get<0>(), b.get<1>()); }
};
template <> struct equal_to<box> {
bool operator()(box const& a, box const& b) const { return
std::tie(a.min_corner().get<0>(), a.min_corner().get<1>(), a.max_corner().get<0>(), a.max_corner().get<1>())
== std::tie(b.min_corner().get<0>(), b.min_corner().get<1>(), b.max_corner().get<0>(), b.max_corner().get<1>()); }
};
}
struct Feature {
box bounds;
//... other members ...
std::string other;
friend std::ostream& operator<<(std::ostream& os, Feature const& f) {
return os << "{" << bg::wkt(f.bounds) << ", " << std::quoted(f.other) << "}";
}
struct less_by_box : std::less<box> {
bool operator()(Feature const& a, Feature const& b) const { return std::less<box>::operator()(a.bounds, b.bounds); }
};
struct by_box : std::equal_to<box> {
bool operator()(Feature const& a, Feature const& b) const { return std::equal_to<box>::operator()(a.bounds, b.bounds); }
};
};
int main() {
std::vector<Feature> v {
{ box { {2,3}, {4,5} }, "three" },
{ box { {1,2}, {3,4} }, "two" },
{ box { {2,3}, {4,5} }, "one" },
};
auto dump = [&] {
std::cout << "Size: " << v.size() << "\n";
for (Feature const& f : v) { std::cout << f << "\n"; }
};
dump();
std::cout << " -- Sort, Unique, Erase:\n";
std::stable_sort(v.begin(), v.end(), Feature::less_by_box{});
v.erase(std::unique(v.begin(), v.end(), Feature::by_box{}), v.end());
dump();
}
Prints
Size: 3
{POLYGON((2 3,2 5,4 5,4 3,2 3)), "three"}
{POLYGON((1 2,1 4,3 4,3 2,1 2)), "two"}
{POLYGON((2 3,2 5,4 5,4 3,2 3)), "one"}
-- Sort, Unique, Erase:
Size: 2
{POLYGON((1 2,1 4,3 4,3 2,1 2)), "two"}
{POLYGON((2 3,2 5,4 5,4 3,2 3)), "three"}
In Python , instead of
colors = ['red', 'green', 'blue', 'yellow']
for i in range(len(colors)):
print i, '--->', colors[i]
One can write
for i, color in enumerate(colors):
print i, '--->', color
Is there a similar thing in c++?
You can actually implement something similar in c++17.
Here is a sketch(c++-ish pseudocode), I use values everywhere and they should be replaced by appropriate references/forwarding, also you should fix how you get types (use iterator_traits), may be support unknown size, may be implement proper iterator interface etc
template <typename T>
struct EnumeratedIterator {
size_t index;
T iterator;
void operator++() {
++iterator;
}
std::pair<size_t, T>() {
return {index, *iterator};
}
bool operator !=(EnumeratedIterator o) {
return iterator != o.iterator;
}
}
template <typename T>
struct Enumerated {
T collection;
EnumeratedIterator<typename T::iterator> begin() {
return {0, collection.begin()};
}
EnumeratedIterator<typename T::iterator> end() {
return {collection.size(), collection.end()};
}
}
auto enumerate(T col) {
return Enumerated<T>(col);
}
and then use it like
for (auto [index, color] : enumerate(vector<int>{5, 7, 10})) {
assert(index < color);
}
Boost provides an adaptor which allows to do something similiar:
http://www.boost.org/doc/libs/1_63_0/libs/range/doc/html/range/reference/adaptors/reference/indexed.html
The following code is taken from the link above
#include <boost/range/adaptor/indexed.hpp>
#include <boost/assign.hpp>
#include <iterator>
#include <iostream>
#include <vector>
int main(int argc, const char* argv[])
{
using namespace boost::assign;
using namespace boost::adaptors;
std::vector<int> input;
input += 10,20,30,40,50,60,70,80,90;
for (const auto& element : input | indexed(0))
{
std::cout << "Element = " << element.value()
<< " Index = " << element.index()
<< std::endl;
}
return 0;
}
Maybe you can emulate it like this:
int i = 0;
for (auto color : { "red", "green", "blue", "yellow" })
std::cout << i++ << "--->" << color << std::endl;
I need to convert an std::unordered_multimap<Key,T> to an std::vector<std::vector<T>>. I need to do this because my program will need to sort all the data, and maps can't be sorted. An example:
// Map:
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
// Map converted to vector<vector<Value>>:
{ 1, 3, 2 },
{ 5, 2 }
Right now I have this code which works. But I'm wondering if it's the best way to do it.
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for ( Map_t::const_iterator it = map.cbegin(); it != map.cend(); )
{
std::vector< Value_t > temp;
const Map_t::const_iterator end = map.upper_bound( it->first );
for ( ; it != end; ++it )
temp.push_back( it->second );
output.push_back( temp );
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
Output:
1 3 2
5 2
So, now I'm wondering if there's a faster/better way.
here's my attempt.
proof is here: http://goo.gl/JVpHw9
#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
typedef std::string Key_t;
typedef int Value_t;
typedef std::unordered_multimap<Key_t, Value_t> Map_t;
const Map_t map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector< std::vector< Value_t > > output;
for (auto it = map.begin(); it != map.end(); )
{
auto er = map.equal_range(it->first);
auto tmp = std::vector< Value_t >{};
for( ; it != er.second ; ++it) {
tmp.push_back(it->second);
};
output.push_back(std::move(tmp));
}
// Print the result
for ( const std::vector< Value_t >& values : output )
{
for ( const Value_t& value : values )
std::cout << value << " ";
std::cout << std::endl;
}
}
The usual multimap iteration should work here:
std::vector<std::vector<T>> out;
for (auto it1 = m.begin(), it2 = it1, end = m.end(); it1 != end; it1 = it2)
{
out.emplace_back();
for ( ; it1->first == it2->first; ++it2)
{
out.back().push_back(it2->second);
}
}
Following works for me:
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
int main () {
std::unordered_multimap<std::string, int> map;
map = {
{ "A", 1 },
{ "A", 3 },
{ "A", 2 },
{ "B", 5 },
{ "B", 2 },
};
std::vector<int> values;
std::transform(map.begin(), map.end(),
std::back_inserter(values),
[](std::pair<std::string, int> element) {
return element.second;
});
for (auto const& value : values) {
std::cout << value << std::endl;
}
return 0;
}
How can I implement STL map sorting by value?
For example, I have a map m:
map<int, int> m;
m[1] = 10;
m[2] = 5;
m[4] = 6;
m[6] = 1;
I'd like to sort that map by m's value. So, if I print the map, I'd like to get the result as follows:
m[6] = 1
m[2] = 5
m[4] = 6
m[1] = 10
How can I sort the map in this way? Is there any way that I can deal with the key and value with sorted values?
Dump out all the key-value pairs into a set<pair<K, V> > first, where the set is constructed with a less-than functor that compares the pair's second value only. That way, your code still works even if your values aren't all distinct.
Or dump the key-value pairs into a vector<pair<K, V> >, then sort that vector with the same less-than functor afterwards.
You can build a second map, with the first map's values as keys and the first map's keys as values.
This works only if all values are distinct. If you cannot assume this, then you need to build a multimap instead of a map.
I wonder how can I implement the STL map sorting by value.
You can’t, by definition. A map is a data structure that sorts its element by key.
You should use Boost.Bimap for this sort of thing.
Based on #swegi's idea, I implemented a solution in c++11 using a multimap:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
multimap<int, int> mm;
for(auto const &kv : m)
mm.insert(make_pair(kv.second, kv.first)); // Flip the pairs.
for(auto const &kv : mm)
cout << "m[" << kv.second << "] = " << kv.first << endl; // Flip the pairs again.
Code on Ideone
I also implemented a C++11 solution based on #Chris' idea using a vector of pairs. For correct sorting, I provide a lambda expression as comparison functor:
map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}};
using mypair = pair<int, int>;
vector<mypair> v(begin(m), end(m));
sort(begin(v), end(v), [](const mypair& a, const mypair& b) { return a.second < b.second; });
for(auto const &p : v)
cout << "m[" << p.first << "] = " << p.second << endl;
Code on Ideone
The first solution is more compact, but both solutions should have roughly the same performance. Inserting into a multimap is of O(log n), but this has to be done for n entries, resulting in O(n log n). Sorting the vector in the second solution also results in O(n log n).
I also gave a try to #Chris' idea on using a set of pairs. However, it won't work if the values aren't all distinct. Using a functor that compares only the pair's second element doesn't help. If you first insert make_pair(1, 1) into the set and then try to insert make_pair(2, 1), then the second pair won't be inserted, because both pairs are seen as identical by that set. You can see that effect here on Ideone.
I've just done a similar question in my c++ book. The answer I came up with might not be very efficient though:
int main()
{
string s;
map<string, int> counters;
while(cin >> s)
++counters[s];
//Get the largest and smallest values from map
int beginPos = smallest_map_value(counters);
int endPos = largest_map_value(counters);
//Increment through smallest value to largest values found
for(int i = beginPos; i <= endPos; ++i)
{
//For each increment, go through the map...
for(map<string, int>::const_iterator it = counters.begin(); it != counters.end(); ++it)
{
//...and print out any pairs with matching values
if(it->second == i)
{
cout << it->first << "\t" << it->second << endl;
}
}
}
return 0;
}
//Find the smallest value for a map<string, int>
int smallest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int lowest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second < lowest)
lowest = it->second;
}
return lowest;
}
//Find the largest value for a map<string, int>
int largest_map_value(const map<string, int>& m)
{
map<string, int>::const_iterator it = m.begin();
int highest = it->second;
for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it)
{
if(it->second > highest)
highest = it->second;
}
return highest;
}
Create another map, provide a less() function based on the value not key, AND the function should return true if the value1 <= value2 (not strictly < ). In this case, elements with non-distinct values can be sorted as well.
I have found this in thispointer. The example sorts a std::map< std::string,int> by all the int values.
#include <map>
#include <set>
#include <algorithm>
#include <functional>
int main() {
// Creating & Initializing a map of String & Ints
std::map<std::string, int> mapOfWordCount = { { "aaa", 10 }, { "ddd", 41 },
{ "bbb", 62 }, { "ccc", 13 } };
// Declaring the type of Predicate that accepts 2 pairs and return a bool
typedef std::function<bool(std::pair<std::string, int>, std::pair<std::string, int>)> Comparator;
// Defining a lambda function to compare two pairs. It will compare two pairs using second field
Comparator compFunctor =
[](std::pair<std::string, int> elem1 ,std::pair<std::string, int> elem2)
{
return elem1.second < elem2.second;
};
// Declaring a set that will store the pairs using above comparision logic
std::set<std::pair<std::string, int>, Comparator> setOfWords(
mapOfWordCount.begin(), mapOfWordCount.end(), compFunctor);
// Iterate over a set using range base for loop
// It will display the items in sorted order of values
for (std::pair<std::string, int> element : setOfWords)
std::cout << element.first << " :: " << element.second << std::endl;
return 0;
}
One thing that could be done in some scenarios, is using a vector<pair<int, int>> rather than using maps<int, int>. In this way you lose the benefits of using map, such as the less lookup time but you can directly use comparator function with vector<pair<int, int>>
bool compare(pair<int, int> a, pair<int, int> b)
{
return (a.second < b.second);
}
Recently had to do this. I ended up using pointers...
Quick Benchmark Results
#include <iostream>
#include <type_traits>
#include <algorithm>
#include <map>
#include <vector>
using map_t = std::map<int,int>;
const map_t m
{
{ 5, 20 },
{ -18, 28 },
{ 24, 49 },
{ 17, 27 },
{ 23, 46 },
{ 8, 16 },
{ -13, 11 },
{ -22, 32 },
{ 12, 45 },
{ -2, 19 },
{ 21, 11 },
{ -12, 25 },
{ -20, 8 },
{ 0, 29 },
{ -5, 20 },
{ 13, 26 },
{ 1, 27 },
{ -14, 3 },
{ 19, 47 },
{ -15, 17 },
{ 16, 1 },
{ -17, 50 },
{ -6, 40 },
{ 15, 24 },
{ 9, 10 }
};
template<typename T>
void sort_values_using_vector(T const& m)
{
using map_t = T;
using sort_t = std::vector<std::pair<typename map_t::key_type,
typename map_t::mapped_type>>;
sort_t sorted{ m.begin(), m.end() };
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs.second < rhs.second;
});
}
template<typename T>
void sort_values_using_multimap(T const& m)
{
using map_t = T;
using sort_t = std::multimap<typename map_t::mapped_type,
typename map_t::key_type>;
sort_t sorted;
for (auto const& kv : m)
{
sorted.insert(std::make_pair(kv.second, kv.first));
}
}
template<typename T>
void sort_values_using_ptrs(T const& m)
{
using map_t = T;
using ptr_t = std::add_pointer_t
<std::add_const_t<typename map_t::value_type>>;
using sort_t = std::vector<ptr_t>;
sort_t sorted;
sorted.reserve(m.size());
for (auto const& kv : m)
{
sorted.push_back(std::addressof(kv));
}
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs->second < rhs->second;
});
}
template<typename T>
void sort_values_using_refs(T const& m)
{
using map_t = T;
using ref_t = std::reference_wrapper
<std::add_const_t<typename map_t::value_type>>;
using sort_t = std::vector<ref_t>;
sort_t sorted{ m.begin(), m.end() };
std::sort(sorted.begin(), sorted.end(),
[](auto const& lhs, auto const& rhs)
{
return lhs.get().second < rhs.get().second;
});
}
static void copy_to_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_vector(m);
}
}
BENCHMARK(copy_to_vector);
static void copy_flipped_to_multimap(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_multimap(m);
}
}
BENCHMARK(copy_flipped_to_multimap);
static void copy_ptrs_to_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_ptrs(m);
}
}
BENCHMARK(copy_ptrs_to_vector);
static void use_refs_in_vector(benchmark::State& state) {
// Code inside this loop is measured repeatedly
for (auto _ : state) {
sort_values_using_refs(m);
}
}
BENCHMARK(use_refs_in_vector);
This code uses custom sorting function to sort map by values
// Comparator function to sort pairs
// according to value
bool comp(pair<int, int>& a,
pair<int, int>& b)
{
return a.second < b.second;
}
// Function to sort the map according
// to value in a (key-value) pair
void customSort(map<int, int>& m)
{
vector<pair<int, int>> a;
for(auto x:m)
a.push_back(make_pair(x.first,x.second));
sort(a.begin(), a.end(), comp);
for (auto x:a) {
cout << x.first<<" "<<x.second<<endl;
}
}