I want to use a map to count pairs of objects based on member input vectors. If there is a better data structure for this purpose, please tell me.
My program returns a list of int vectors. Each int vector is the output of a comparison between two int vectors ( a pair of int vectors). It is, however, possible, that the output of the comparison differs, though the two int vectors are the same (maybe in different order). I want to store how many different outputs (int vectors) each pair of int vectors has produced.
Assuming that I can access the int vector of my object with .inp()
Two pairs (a1,b1) and (a2,b2) should be considered equal, when (a1.inp() == a2.inp() && b2.inp() == b1.inp()) or (a1.inp() == b2.inp() and b1.inp() == a2.inp()).
This answer says:
The keys in a map a and b are equivalent by definition when neither a
< b nor b < a is true.
class SomeClass
{
vector <int> m_inputs;
public:
//constructor, setter...
vector<int> inp() {return m_inputs};
}
typedef pair < SomeClass, SomeClass > InputsPair;
typedef map < InputsPair, size_t, MyPairComparator > InputsPairCounter;
So the question is, how can I define equivalency of two pairs with a map comparator. I tried to concatenate the two vectors of a pair, but that leads to (010,1) == (01,01), which is not what I want.
struct MyPairComparator
{
bool operator() (const InputsPair & pair1, const InputsPair pair2) const
{
vector<int> itrc1 = pair1.first->inp();
vector<int> itrc2 = pair1.second->inp();
vector<int> itrc3 = pair2.first->inp();
vector<int> itrc4 = pair2.second->inp();
// ?
return itrc1 < itrc3;
}
};
I want to use a map to count pairs of input vectors. If there is a better data structure for this purpose, please tell me.
Using std::unordered_map can be considered instead due to 2 reasons:
if hash implemented properly it could be faster than std::map
you only need to implement hash and operator== instead of operator<, and operator== is trivial in this case
Details on how implement hash for std::vector can be found here. In your case possible solution could be to join both vectors into one, sort it and then use that method to calculate the hash. This is straightforward solution, but can produce to many hash collisions and lead to worse performance. To suggest better alternative would require knowledge of the data used.
As I understand, you want:
struct MyPairComparator
{
bool operator() (const InputsPair& lhs, const InputsPair pair2) const
{
return std::minmax(std::get<0>(lhs), std::get<1>(lhs))
< std::minmax(std::get<0>(rhs), std::get<1>(rhs));
}
};
we order the pair {a, b} so that a < b, then we use regular comparison.
Related
This question already has answers here:
operator< comparing multiple fields
(6 answers)
Closed 3 years ago.
Consider implementing operator< for the following class:
struct foo {
int a, b;
};
Probably the most common way is something like the element-wise lexicographic compare, like so:
bool operator<(foo lhs, foo rhs) {
return lhs.a < rhs.a || (lhs.a == rhs.a && lhs.b < rhs.b);
}
I've written that enough times, and made a type enough times that I'm wondering if there is something built in to std:: that will do it for me, hopefully with less boilerplate and reasonable code generation.
Now the above for two elements isn't that bad, but the terms multiply as you add more members.
You can use pair<int, int> instead of struct foo.
As pair<type,type> is builtin in std:: it has comparator for all builtin data type. So you don't need any extra operator overloading or a custom comparator. Even it works for strings. std:: compare two pair<type, type> based on the first element of the pair. If it's a tie then the tie is broken based on the second element.
For example-
pair<int,int> a = make_pair(5,10) //declare using make_pair()
pair<int,int> b = {5,7} //different way of declaring pair.
pair<int,int> c = pair<int,int>(7,7) //declare using constructor
Now a < b == false, b < c == true and a < c == true
So in this way, you can use pair<type, type> instead of struct foo. You can replace 'type' using any data type like float, long long, char, string, pair, vector, set, map, complex etc.
The program receives a vector that represents a character.
It then compares the received vector with all the known vectors that represents characters.
I'm not sure how should I use the known vectors.
A few options I thought of:
1) Using global variables:
vector<int> charA{1,2,3,4,5};
vector<int> charB{5,3,7,1};
...
vector<int> charZ{3,2,5,6,8,9,0}
char getLetter(const vector<int> &input){
if(compareVec(input,charA) return 'A';
if(compareVec(input,charB) return 'B';
....
if(compareVec(input,charZ) return 'Z';
}
2) Declaring all variables in function:
char getLetter(const vector<int> &input){
vector<int> charA{1,2,3,4,5};
vector<int> charB{5,3,7,1};
...
vector<int> charZ{3,2,5,6,8,9,0}
if(compareVec(input,charA) return 'A';
if(compareVec(input,charB) return 'B';
....
if(compareVec(input,charZ) return 'Z';
}
3) Passing the variables
char getLetter(const vector<int> &input, vector<int> charA,
vector<int> charB... , vecotr<int> charZ){
if(compareVec(input,charA) return 'A';
if(compareVec(input,charB) return 'B';
....
if(compareVec(input,charZ) return 'Z';
}
This sounds like an application for a perfect hash generator (link to GNU gperf).
To quote the documentation
gperf is a perfect hash function generator written in C++. It
transforms an n element user-specified keyword set W into a perfect
hash function F. F uniquely maps keywords in W onto the range 0..k,
where k >= n-1. If k = n-1 then F is a minimal perfect hash function.
gperf generates a 0..k element static lookup table and a pair of C
functions. These functions determine whether a given character string
s occurs in W, using at most one probe into the lookup table.
If this is not a suitable solution then I'd recommend using function statics. You want to avoid function locals as this will badly affect performance, and globals will pollute your namespace.
So something like
char getLetter(const vector<int> &input){
static vector<int> charA{1,2,3,4,5};
static vector<int> charB{5,3,7,1};
Giving you snippet, I'd go for:
char getLetter(const vector<int> &input)
{
struct
{
char result;
std::vector<char> data;
} const data[]=
{
{ 'A', {1,2,3,4,5}, },
{ 'B', {5,3,7,1}, },
...
};
for(auto const & probe : data)
{
if (comparevec(input, probe.data))
return probe.result;
}
// input does not match any of the given values
throw "That's not the input I'm looking for!";
}
For 40 such pairs, if this is not called in a tight inner loop, the linear search is good enough.
Alternatives:
use a std::map<std::vector<char>, char> to map valid values to results, and turn compareVec into a functor suitable as key-comaprison for the map, and initialize it the same way.
as above, but use a std::unordered_map.
use gperf, as suggested by #PaulFloyd above
I would start by suggesting that you hash or represent the numbers in their binary collection so that you are not comparing vectors each time as that would prove very costly. That said, your question is about how to make a dictionary, so whether you improve your keys as I suggested or not, I'd prefer the use of a map:
map<vector<int>, char, function<bool(const vector<int>&, const vector<int>&)>> dictionary([](const auto& lhs, const auto& rhs){
const auto its = mismatch(cbegin(lhs), cend(lhs), cbegin(rhs), cend(rhs));
return its.second != cend(rhs) && (its.first == cend(lhs) || *its.first < *its.second);
});
If possible dictionary should be constructed constant with an initializer_list containing all mappings and the comparator. If mappings must be looked up before you are guaranteed to have finished all letters then you obviously can't construct constant. Either way this map should be a private member of the class responsible for translating strings. Adding and mapping should be public functions of the class.
Live Example
Given a vector of unordered_map<u_int,int>,
I would like to check if the vector contains any duplicated values. Two unordered_maps are considered duplicated if all of their keys and their corresponding values are equal.
I know the comparison operator exists for unordered_maps, but I would like to avoid the pairwise comparison of each element with each other. One classical solution is to insert the values of the vector into a set, then to compare the number of elements in the set and the vector.
However, the problem here is that the object to be inserted into the set must have the comparison operators overloaded. In case of the unordered_set, the hash function to be used must be overloaded for the complex object. In order to overload, I need to derive a class from the std::unordered_map. Then I need to overload either the comparison operator or the hash function. Another solution that I could think of is to concatenate all of the key value pairs into a string, then sort the string by the keys and detect the duplicates on those strings. I wonder what would be the best solution for this problem.
Example data:
using namespace std;
typedef unordered_map<u_int,int> int_map;
int_map a = { {1,1}, {2,4}, {3,5} };
int_map b = { {1,1}, {2,-1}, {4,-2} };
int_map c = { {1,1}, {3,5} };
vector<unordered_map<u_int,int>> my_vec;
my_vec.push_back(a);
my_vec.push_back(b);
my_vec.push_back(c);
The contents of my_vec is:
{ { 1 => 1, 2 => 4, 3 => 5 },
{ 1 => 1, 2 => -1, 4 => -2 },
{ 1 => 1, 3 => 5 } }
Please feel free to ask/commend/edit if the question is not clear enough.
Any help would be appreciated. Thank you in advance!
you can something similar to the following :
typedef unordered_map<u_int,int> int_map;
struct my_map_comparator
{
bool operator()(const int_map& a, const int_map& b)
{
a_hash = compute_hash_for_a(all keys of a)
b_hash = compute_hash_for_b(all keys of b)
return a_hash == b_hash;
}
};
std::unordered_set<int_map,std::hash<int_map>, my_map_comparator> map_list();
If you can get a good hash function for std::unordered_map then you should do it like this probably:
bool has_distinct_values(const std::vector<std::unordered_map<u_int, int>> v)
{
std::unordered_map<int, std::list<int>> hash_to_indexes_map;
for(auto i = 0u; i < v.size(); ++i)
{
auto empl_result = hash_to_index_map.emplace(custom_hash(v[i]), {i});
if (!empl_result.second)
{
for (auto index : empl_result.first->second)
{
if (v[index] == v[i]) return false;
}
empl_result.first->second.push_back(i);
}
}
return true;
}
The algorithm is straightforward: map hashes to list indexes, doing pairwise map comparison whenever hashes are equal.
This way you avoid copying the entire maps, get O(N) (depending mostly on the quality of the hash function you provide) time complexity and generally are good to go.
I would like to compare a vector with an array assuming that elements are in different order.
I have got a struct like below:
struct A
{
int index;
A() : index(0) {}
};
The size of the vector and the array is the same:
std::vector<A> l_v = {A(1), A(2), A(3)};
A l_a[3] = {A(3), A(1), A(2)};
The function to compare elements is:
bool isTheSame()
{
return std::equal(l_v.begin(), l_v.end(), l_a,
[](const A& lhs, const A& rhs){
return lhs.index == rhs.index;
});
}
The problem is that my function will return false, because the elements are the same, but not in the same order.
A solution is to sort the elements in the vector and array before "std::equal", but is there any better solution?
Using sort would be the way to go. Sorting in general is a good idea. And as far as I know it would result in the best performance.
Note: I would recommend passing the vectors as arguments. Rather than using the member variables. After doing that this would be a typical function that would be very well suited to inline. Also you might also want to consider taking it out of the class and/or making it static.
I'm trying to sort an Eigen VectorXf x in ascending order.
This sorts it in descending order:
std::sort(x.data(),x.data()+x.size());
and this doesn't work:
bool myfunction (int i,int j) { return (i<j); }
std::sort(x.data(),x.data()+x.size(),myfunction);
any ideas?
Preface
Since the original question turned out to be a misunderstanding, and the code in it is already the proper answer, I decided to write up and post a bit about using std::sort in general.
std::sort sorts range in ascending order defined by weak ordering of the elements. By default it uses < operator defined on elements, but it can also take a function object or functor to provide the comparison. This functor needs to have properly overloaded function with signature of bool operator()(const T& lhs, const T& rhs) const. An example of this follows:
struct FooSorter {
bool operator (const Foo& lhs, const Foo& rhs) const {
return lhs.ham_index < rhs.ham_index;
}
};
/* ... */
std::sort(begin(vec), end(vec), FooSorter());
This would sort the full range represented by vec, according to criteria defined in FooSorter's operator().
Because writing custom functors for the simple things (sort in descending order, sort in ascending order) would quickly grow painful, STL provides many templated functors ready to use in functional header. The one relevant for sorting are:
std::equal_to implementing x == y
std::not_equal_to implementing x != y
std::greater implementing x > y
std::less implementing x < y
std::greater_equal implementing x >= y
std::less_equal implementing x <= y
All of these are templated and can be used for any type, that implements needed operators. Using these is easy:
std::sort(begin(vec), end(vec), std::greater<int>());
This would sort the range represented by vector in descending order.
But, since one of the biggest problems of STL algorithms was the pain of defining functors, C++11 brings a new trick: lambda functions. This lets you declare function object equivalent inline. Example follows:
std::sort(begin(vec), end(vec), [](int lhs, int rhs){return rhs > lhs});
This would also sort the range represented by vector in descending order, but we didn't have to explicitly declare a functor (or use already declared one). (This gets much better when implementing much more complex comparisons, or functors for different STL algorithms.)
If someone is looking for an answer, here how I did it. In this way, you can get eigenvalues and corresponding eigenvectors as well. Here covariance_matrix is the matrix in which eigenvalues and eigenvectors are to be solved.
std::vector<std::tuple<float, Eigen::VectorXf>> eigen_vectors_and_values;
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eigensolver(covariance_matrix);
if (eigensolver.info() != Eigen::Success) {
return;
}
Eigen::VectorXf eigen_values = eigensolver.eigenvalues();
Eigen::MatrixXf eigen_vectors = eigensolver.eigenvectors();
for(int i=0; i<eigen_values.size(); i++){
std::tuple<float, Eigen::VectorXf> vec_and_val(eigen_values[i], eigen_vectors.row(i));
eigen_vectors_and_values.push_back(vec_and_val);
}
std::sort(eigen_vectors_and_values.begin(), eigen_vectors_and_values.end(),
[&](const std::tuple<float, Eigen::VectorXf>& a, const std::tuple<float, Eigen::VectorXf>& b) -> bool{
return std::get<0>(a) < std::get<0>(b);
});
Note: Be careful when selecting which eigensolver is to be used. You may find here which one to be used: https://eigen.tuxfamily.org/dox/group__Eigenvalues__Module.html
Thanks for this complete answer for sorting both, eigenvalues and eigenvectors. Is it correct to return row() in
std::tuple<float, Eigen::VectorXf> vec_and_val(eigen_values[i], eigen_vectors.row(i));
From what is stated in the documentation of Eigen, it should be col()