Find max/min value of a member class in a container - c++

I have a vector/container of classes and I want to find the element that has the max/min value of a specific member; for example:
#include <vector>
struct A {
int val;
};
int main() {
std::vector<A> v{{1},{2},{3}};
// how do I find the maximum of .val inside the vector?
}
Is there an "STL" way to find the item without explicitly iterating over the container and compare the values?
A comment on the two solutions
I'll add here a solution based on #Jarod42 comment on the accepted solution, based on std::ranges::less{} :
#include <iostream>
#include <vector>
#include <algorithm>
struct A {
int val1;
int val2;
};
int main()
{
std::vector<A> v{{6,8}, {4,10}, {5,12}};
// How can I find out the minimum and maximum?
const auto [min, max] = std::ranges::minmax_element(v, std::ranges::less{}, &A::val1);
std::cout << "Minimum Number: " << min->val1 << '\n';
std::cout << "Maximum Number: " << max->val1 << '\n';
}
I prefer this solution when the comparison to determine the min/max value is trivial, while the accepted solution is more generic and can be used when the definition of "less than" is complex.
Not sure if it needs C++20's ranges, but I'm using C++20 anyway so for the moment I won't investigate it any further.

There are various ways:
std::min
std::min_element
For example:
auto smallest = std::min_element(v.begin(), v.end(), [](const A v1, const A v2) {
return v1.val < v2.val;
});
std::cout << "Smallest: " << smallest->val << "\n";

Related

Is it possible to put lambda expressions into a map or list in C++?

#DanielLangr #luxun #cdhowie sorry for the XY problem. i am not sure i can explain well, but i try my best. the situation is almost like this: there is a base object "Worker" and some children. chef、tailor... children has the same action like walk、run、sleep...but different skill,chef can make food, tailor can Make clothes. Invoker call Worker dothings but do not exactly know their profession.so i add a interface dothings(Thing) on Worker the base object. Thing is an enum,value is MakeFood、MakeClothes...
Worker *w = new Chef();
w->dothings(MakeFood);//
w->dothings(MakeClothes);//throw exception "w do not have skill"
so i think meybe use a container in children that describe what it can do and how to do.
hope i explained clearly.and is there a better solution?
I want to put different lambda expressions into a list or Qmap, like below.
Qmap<String, lambda> map;
map.insert("first",[](int i) -> int {return i;});
map.insert("second",[](string s) -> string {return s;});
Is it possible in C++? And what is the type of lambda?
It is possible but using function wrapper.
For example,
std::map<std::string, std::function<void(std::string)>> my_map;
my_map.emplace("first", [](std::string i) { std::cout << i << std::endl; });
However, if you want to pass any type of argument to your function and return any type from your lambda/function, use boost::any. You also use std::any if you are using C++17 or above.
EDIT:
A working example:
#include <iostream>
#include <string>
#include <functional>
#include <map>
#include <boost/any.hpp>
int main()
{
auto any = [](boost::any i)
{
std::cout << "In any" << std::endl;
if (i.type() == typeid(int))
std::cout << boost::any_cast<int>(i) << std::endl;
return boost::any(1000);
};
std::map<std::string, std::function<boost::any(boost::any)>> my_map;
my_map.emplace("first", any);
my_map.emplace("second", [](boost::any i) -> boost::any { });
auto ret = my_map["first"](100);
std::cout << boost::any_cast<int>(ret) << std::endl;
return 0;
}
Outputs:
In any
100
1000
With any, the solution may look like as follows:
auto lambda1 = [](int i) { return i; };
auto lambda2 = [](std::string s) { return s; };
std::map<std::string, std::any> map;
map["first"] = lambda1;
map["second"] = lambda2;
std::cout << std::any_cast<decltype(lambda1)>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<decltype(lambda2)>(map["second"])("hello") << std::endl;
I am not familiar with Qmap and String, so I used the types from the C++ Standard Library.
Live demo: https://godbolt.org/z/8XK8de
Alternatively, you can also additionally use std::function if you want to avoid those decltypes:
std::map<std::string, std::any> map;
map["first"] = std::function<int(int)>( [](int i) { return i; } );
map["second"] = std::function<std::string(std::string)>( [](std::string s) { return s; } );
std::cout << std::any_cast<std::function<int(int)>>(map["first"])(-1) << std::endl;
std::cout << std::any_cast<std::function<std::string(std::string)>>(map["second"])("hello") << std::endl
Live demo: https://godbolt.org/z/XAc3Q2
However, as other pointed out to, this really seems to be an XY problem.
It is possible as long as you are trying to insert the same lambda type ( your example has different lambda types) You have to be careful how you do it but it does work. For example
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map.emplace(0,factory(0));
map.emplace(7,factory(7));
std::cout << map.at(0)(3) << std::endl ;
std::cout << map.at(7)(3) << std::endl ;
}
outputs
3
10
as expected and not a std::function in sight! However the following does not work
#include <iostream>
#include <map>
int main(){
auto factory = [](int i){
return [=](int j){return i+j;};
};
using L = decltype(factory(0));
std::map<int,L> map;
map[0]=factory(0);
map[7]=factory(7);
std::cout << map[0](3) << std::endl ;
std::cout << map[7](3) << std::endl ;
}
Using the indexing operator tries to use copy assignment whereas emplace doesn't.
https://godbolt.org/z/co1vno6xb

Python's enumerate for C++ [duplicate]

This question already has answers here:
How to find the index of current object in range-based for loop?
(12 answers)
Closed 4 years ago.
In Python there is enumerate which takes a sequence/iterator and yields pairs of an integer index and the value itself. In C++ I occasionally find myself writing
for (size_t i = 0; i != vector.size(); ++i) {
auto const &elem = vector[i];
// ...
Similar to Python I would like to write
for (auto const &it : enumerate(vector)) {
// it.first is the index (size_t)
// it.second is the element (T const&)
Does such an enumerate exist in either the STL or a common library like Boost?
Yes, this is what Boost's adapators::indexed does.
Their example (which also uses the now-redundant Boost.Assign for terse container initialisation) follows:
#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;
}
Nothing in the standard library, though it's not hard to write.
Here is an example using range-v3. A bit more verbose than a handcrafted solution, but it's nice IMHO how you can assemble such a range from existing views.
#include <range/v3/view/indices.hpp>
#include <range/v3/view/zip.hpp>
using namespace ranges;
std::vector<int> vec{42, 43, 44};
for (const auto& idxAndValue : view::zip(view::indices, vec))
std::cout << ideAndValue.first << " : " << idxAndValue.second << "\n";;
Another way that only works:
with references to elements, and
array-based containers, and
elements do not overload operator&
for(auto const &it : vector) {
size_t index = &it - vector.data();
}
Here's a version using an higher-order function. I like it because it's simple to implement and doesn't require you to know the nuances of structured bindings. It also doesn't require any extra dependency.
template <typename Container, typename F>
void enumerate(Container&& c, F&& f)
{
std::size_t i = 0;
for(auto&& x : std::forward<Container>(c))
{
f(i++, forward_like<Container>(x));
}
}
(Where forward_like moves x if Container is an rvalue.)
Usage:
enumerate(std::vector{'a', 'b', 'c'}, [](auto index, auto x)
{
std::cout << index << ": " << x << '\n';
});
Prints:
0: 'a'
1: 'b'
2: 'c'
live example on wandbox.org
C++11 compliant version: live example on wandbox.org

I want to reverse the values of map and print it using range based for loop.

I have done the programming but it is not reversing. I have used a different map to put the values in reverse order,but it still shows the same. My main question was to traverse backward and print the values using range based loop.
#include "stdafx.h"
#include <iostream>
#include<conio.h>
#include <stdio.h>
#include<vector>
#include<map>
#include<utility>
#include<set>
map<int, int>m1;
for (int i = 1; i <= 100; ++i)
{
m1.insert({ i,i });
}
for (const auto &y :m1)
{
cout <<"("<< y.first << " "<<y.second << ")" <<" " ;
}
cout << endl << endl;
map<int, int>m2;
map<int, int>::reverse_iterator iter;
for (auto iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
m2.insert({ iter->first,iter->second });
}
for (const auto &y : m2)
{
cout << "(" << y.first << " " << y.second << ")" << " ";
}
As Some Programmer Dude pointed out, but for the completeness of my answer, a std::map is sorted on the key, no matter what order you insert the elements. One option would be to create a new map with the opposite sorting, but that doesn't seem to be what you really want.
It seems you know how about reverse iterators, but not how to get at them when using range-based for. Since it operates on a range, i.e. some type that provides begin and end iterators, you need to create some wrapper around your map that provides this.
Here's a general one I just put together than works in C++11. It won't cover every possible case, and can be made a bit neater in C++14, but it will work for you.
#include <iostream>
#include <iterator>
// The wrapper type that does reversal
template <typename Range>
class Reverser {
Range& r_;
public:
using iterator_type = std::reverse_iterator<decltype(std::begin(r_))>;
Reverser(Range& r) : r_(r) {}
iterator_type begin() { return iterator_type(std::end(r_)); }
iterator_type end() { return iterator_type(std::begin(r_)); }
};
// Helper creation function
template <typename Range>
Reverser<Range> reverse(Range& r)
{
return Reverser<Range>(r);
}
int main()
{
int vals[] = {1, 2, 3, 4, 5};
for (auto i : reverse(vals))
std::cout << i << '\n';
}
This outputs:
$ ./reverse
5
4
3
2
1
(You may also find libraries that provide a similar adapter; Eric Niebler is working on a ranges library for The Standard.)
Also, please reconsider your use of what are often considered bad practices: using namespace std; and endl (those are links to explanations).
Here's an example of iterating backward through a std::map:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, int> m;
m[1] = 1;
m[2] = 2;
m[3] = 3;
for (auto iter = m.rbegin(); iter != m.rend(); ++iter) {
std::cout << iter->first << ": " << iter->second << std::endl;
}
}
If you are pre-C++11, you'll just need to spell out auto, which is:
std::map<int, int>::reverse_iterator
If you're using boost, you can use a range-based for loop with a reverse adapter:
#include <boost/range/adaptor/reversed.hpp>
for (auto& iter : boost::adaptors::reverse(m)) {
std::cout << iter.first << ": " << iter.second << std::endl;
}
If you only need to print the elements in the map in reverse order,you don't need another map for it,you can do this:
std::map<int, int>::reverse_iterator iter;
for (iter = m1.rbegin(); iter != m1.rend(); ++iter)
{
std::cout << "(" << iter->first << " " << iter->second << ")" << " ";
}

What's the efficient way to count duplicates of each pair of a vector?

Is there any efficient way to count duplicates of each pair in a vector?
For example, if I have a vector like this:
vector<pair<int, int> > duplicates={{1,2},{3,2},{2,1},{5,6},{5,6},{1,2},{2,1},{5,6}};
The output should be:
{1,2}:2
{3,2}:1
{2,1}:2
{5,6}:3
And TO be CLEAR, I am just curious about how to solve this problem more efficiently. I have tried to compare each pair of this vector and it seems not a smart way.
An easy way is to use a map or unordered map to count them:
#include <iostream>
#include <vector>
#include <map>
int main( int argn, char **argc)
{
std::vector<std::pair<int, int> > duplicates={{1,2},{3,2},{2,1},{5,6},{5,6},{1,2},{2,1},{5,6}};
std::map<std::pair<int, int>, int> checker;
for (const auto &elem: duplicates)
{
++checker[elem];
}
for (const auto &elem: checker) std::cout << "{" << elem.first.first <<
"," << elem.first.second <<
"}: " << elem.second << std::endl;
return 0;
}
Note that map insertion/recovery is O(log(n)), and the loop around make it aprox. O(n*log(n))
EDIT:
Following the additional note of the OP, here is a better (faster) implementation using unordered_map:
#include <iostream>
#include <vector>
#include <unordered_map>
namespace std
{
template <>
struct hash<std::pair<int,int>>
{
size_t operator()(pair<int, int> const &p) const
{
// Fine for 64bit size_t and 32bit int. Otherwise, some collision may happens.
size_t result = (static_cast<size_t>(p.first) <<(sizeof(std::size_t)<<2))
+ static_cast<size_t>(p.second);
return result;
}
};
}
int main( int argn, char **argc)
{
std::vector<std::pair<int, int> > duplicates={{1,2},{3,2},{2,1},{5,6},{5,6},{1,2},{2,1},{5,6}};
std::unordered_map<std::pair<int, int>, int> checker;
for (const auto &elem: duplicates)
{
++checker[elem]; // value initialized with 0
}
for (const auto &elem: checker) std::cout << "{" << elem.first.first <<
"," << elem.first.second <<
"}: " << elem.second << std::endl;
return 0;
}
Insertion in unordered_map, using a hash make it usually constant (worse case when there are collision is linear). Final complexity in average is O(N)
I have a simple solution:
Sort vector of pairs
Then just a loop if match consecutive pairs then increase counter
General search Complexity: n*n
This search Complexity: nlog(n)

Sort a vector using its elements

i need to know how can we sort a vector of user define class using its elements.
Say i have a class called "coordinates" with getX and getY method that return an int value.
I have created and array of vector "vector PointTwoD vcP2D(5);"
class coordinates {
int getX();
int getY();
)
Now the issue,
1) I need to sort the vector "vcP2D" using getX() and sort in asc order
2) Say an user enters the "2" as the x coordinate. And using that info i need to find which vector contains 2
Please advice
This will do:
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d){ return c.getX() < d.getX(); });
It uses a C++11 Lambda expression as a binary predicate for std::sort.
A short demonstration:
#include <algorithm>
#include <vector>
#include <iostream>
struct coordinates
{
int x;
int y;
};
int main()
{
std::vector<coordinates> v{ {2,3}, {0,0}, {1,5} };
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d) { return c.x < d.x; });
std::cout << "sorted by x values, values of \"x\": " << v[0].x << " " << v[1].x << " " << v[2].x << "\n";
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d) { return c.y < d.y; });
std::cout << "sorted by y values, values of \"x\": " << v[0].x << " " << v[1].x << " " << v[2].x << "\n";
}
A demo of how to find an element in the same way:
#include <algorithm>
#include <vector>
#include <iostream>
struct coordinates
{
int x;
int y;
};
int main()
{
std::vector<coordinates> v{ {2,3}, {0,0}, {1,5} };
auto result = std::find_if(v.begin(), v.end(), [](const coordinates& c){ return c.x == 1 && c.y == 5; });
if(result != v.end())
std::cout << "point (1,5) is number " << std::distance(v.begin(), result)+1 << " in the vector.\n";
else
std::cout << "point (1,5) not found.\n";
}
If you are looking to search in the sorted vector, you can use std::binary_search which takes a comparison function (the same as std::sort above). It also does not give an iterator to that element, only a true or false.
You need to define a strict weak order on your elements, either using operator< () or a binary predicate, and then use std::sort().
The easiest approach is to create a less than operator<():
bool operator< (coordinates const& c0, coordinates const& c1) {
// return a suitable result of comparing c0 and c1 such that operator<()
// become a strict weak order
}
With this all you need to do to sort a std::vector<coordinates> is to use std::sort(). To locate a specific object you would use std::lower_bound().