How can the unordered_set can hold both (0, 1) and (1, 0) if they have the same hash value?
#include <iostream>
#include <unordered_set>
#include <utility>
using namespace std;
struct PairHash
{
template <class T1, class T2>
size_t operator()(pair<T1, T2> const &p) const
{
size_t hash_first = hash<T1>{}(p.first);
size_t hash_second = hash<T2>{}(p.second);
size_t hash_combined = hash_first ^ hash_second;
cout << hash_first << ", " << hash_second << ", " << hash_combined << endl;
return hash_combined;
}
};
int main()
{
unordered_set<pair<int, int>, PairHash> map;
map.insert({0, 1});
map.insert({1, 0});
cout << map.size() << endl;
for (auto& entry : map) {
cout << entry.first << ", " << entry.second << endl;
}
return 0;
}
Output:
0, 1, 1
1, 0, 1
2
1, 0
0, 1
Link to onlinegdb.
unordered_set can hold one instance of any unique data-value; it is not limited to only holding data-values with unique hash-values. In particular, when two data-values are different (according to their == operator) but both hash to the same hash-value, the unordered_set will make arrangements to hold both of them regardless, usually at a slightly reduced efficiency (since any hash-based lookups for either of them will internally hash to a data structure that holds both of them, which the unordered_set's lookup-code will have to iterate over until it finds the one it is looking for)
Related
I am trying to use the unordered_map in C++, such that, for the key I have a string, while for the value there is an array of floats.
std::unordered_map<std::string, std::array<float, 3>> umap;
But, I am not sure how to access the array of values. I know to access the elements, an iterator is an option, but how specifically elements of an array can be accessed?
I am trying to assign these array values to different array (std::array mapArrayVal)
I tried using
for (auto i = umap.begin(); i != umap.end(); i++)
{
std::array<float, 3> mapArrayVal = (i->second.first, i->second.second,
i>second.third);
}
is the correct way? Any help is appreciated, TIA!
This example shows you how to do it with some comments to help you on your way :
#include <array>
#include <iostream>
#include <string>
#include <unordered_map>
int main()
{
// a map consists of key,value pairs in your case
// the key will have a type of std::string
// the value will be an std::array (with three entries)
std::unordered_map<std::string, std::array<float, 3>> umap{
{"key1", {1.0,2.0,3.0}},
{"key2", {4.0,5.0,6.0}}
};
// iterate over all entries using an explicitly type it
// normally you would type auto i.o. std::unordered_map<std::string, std::array<float, 3>>::iterator
// but this shows all the types involved
for (std::unordered_map<std::string, std::array<float, 3>>::iterator it = umap.begin(); it != umap.end(); ++it)
{
// access key/values by iterator it->second will be the array
std::cout << "key = `" << it->first << "`, values : {" << (it->second)[0] << ", " << (it->second)[1] << ", " << (it->second)[2] << "}\n";
}
// however with c++ you could do it in a much more readable way
// combine range based for loop : https://en.cppreference.com/w/cpp/language/range-for
// with structured binding : https://en.cppreference.com/w/cpp/language/structured_binding
// the key_value_pair is const since you only want to observe it for printing
for (const auto& [key, values] : umap)
{
std::cout << "key = `" << key << "`, values : {" << values[0] << ", " << values[1] << ", " << values[2] << "}\n";
}
// use at(key) in map don't use operator[] it may insert an "empty" item in the map if something isn't found there!
auto& reference_to_array_in_map = umap.at("key1");
// this is how you make a copy of the array
std::array<float, 3> copied_values{ reference_to_array_in_map };
for (const float value : copied_values)
{
std::cout << value << " ";
}
std::cout << "\n";
return 0;
}
I was just reading about pairs in C++ when this doubt stroke my mind that how the pairs are stored in memory and id the identifier assigned to the pairs a object or something else.
pls explain how an array containing pair uses memory to save the pairs and how can we iterate through the that array, by accessing each pair;
As for the pair itself, if you take a look at the standard library source code you'll just notice, that after cutting all the boilerplate, the for the most trivial case std::pair is just a simple class template:
template<typename First, typename Second>
struct pair
{
First first;
Second second;
};
Now, all the boilerplate is there to ensure the all the special functions like comparison, assignment, copy construction etc. are performed with minimal overhead.
But for the sake of mental model one can think of this simple struct.
As for "array of pairs" - I'm not sure I follow, really.
std::array<std::pair<X,Y>, SIZE>/std::vector<std::pair<X,Y>> behaves just as it would for any other type, i.e. it store the pairs in contiguous memory block, end of story.
Same about iteration, there's nothing special about it:
std::array<std::pair<char, int>, 3> pairs{
std::pair{'a', 1},
std::pair{'b', 2},
std::pair{'c', 3}};
for (const auto& p:pairs){
std::cout << p.first << " " << p.second << "\n";
}
demo
Take a look at this example:
#include <iostream>
#include <array>
#include <iterator>
int main( )
{
std::array< std::pair<char, char>, 10 > arrayOfPairs { };
std::cout << "size of array: " << sizeof( arrayOfPairs ) << "\n\n";
for ( size_t idx { }; idx < arrayOfPairs.size( ); ++idx) // fill the array with
// std::pair objects
{
arrayOfPairs[ idx ] = std::make_pair<char, char>( 'a', 'b' + idx );
}
std::cout << "key" << " " << "value" << '\n';
for ( const auto& p : arrayOfPairs ) // print the keys and values
{
std::cout << " " << p.first << " " << p.second << '\n';
}
return 0;
}
Output:
size of array: 20
key value
a b
a c
a d
a e
a f
a g
a h
a i
a j
a k
In this example, each pair object consists of two chars, so the size is 2 bytes. arrayOfPairs has the space for 10 pair objects which means that its size is 10 * 2 == 20 bytes. In an std::pair object, the key and its value are stored besides each other. It acts like a simple struct.
I have to construct an ordered container (which must be iterable) with the following rule:
If the condition is true, the container is {1,0}, else it's {0,1}
I have the following code, but I don't find it "elegant":
vector<int> orderedSides;
if (condition)
{
orderedSides.push_back(1);
orderedSides.push_back(0);
}
else
{
orderedSides.push_back(0);
orderedSides.push_back(1);
}
Is there a better way to do this (from concision and performance point of view)?
You might implement something like this:
vector<int> orderedSides(2, 0);
(condition ? orderedSides.front() : orderedSides.back()) = 1;
which is a little bit shorter than explicit if clauses.
As #Deduplicator mentioned below, we might rewrite the second line in a more concise way:
orderedSides[!condition] = 1;
vector<int> orderedSides;
orderedSides.push_back(condition ? 1 : 0);
orderedSides.push_back(condition ? 0 : 1);
I don't think it's more performant but I find it more elegant.
You could compromise between efficiency and avoiding repetition, initialise the first with the condition and the second from the first.
vector<int> orderedSides(1, bool(condition)) ;
orderedSides.push_back(!orderedSides.back());
orderedSides.push_back(0);
orderedSides.push_back(1);
if (condition)
std::iter_swap(orderedSides.begin(), orderedSides.begin()+1);
I know this take bits cost. As one of candidates.
If building the elements (the ints in your question, whatever it is in real life) is free and side-effect-less:
static const int data[] = { 0, 1, 0 };
std::vector<int> orderedSides (data+condition, data+condition+2);
Full program example:
#include <iostream>
#include <vector>
std::vector<int> make(bool cond)
{
static const int data[] = { 0, 1, 0 };
return std::vector<int> (data+cond, data+cond+2);
}
std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
{
return os << "{ " << v[0] << ", " << v[1] << " }";
}
int main()
{
std::cout << "true: " << make(true) << "\n"
<< "false: " << make(false) << "\n";
}
Prints:
true: { 1, 0 }
false: { 0, 1 }
Demo
You can populate a std::vector from an array, even in C++98.
Here's an example:
#include <iostream>
#include <vector>
int main() {
bool condition = false;
std::cout << "condition is: " << std::boolalpha << condition << '\n';
int arr[][2] = {{0,1}, {1,0}};
int index = condition;
std::vector<int> v(arr[index], arr[index]+2);
for (int i = 0; i < v.size(); i++)
std::cout << v[i] << ' ';
std::cout << '\n';
}
The output is:
$ g++ tt.cc && ./a.out
condition is: false
0 1
For reference:
http://en.cppreference.com/w/cpp/container/vector/vector
I am using a C++ STL set with a custom comparator to store an Edge data structure as shown below. I defined the Edge to be essentially a key-value pair. Index is the key and I want to iterate through the collection by value (maxlength) from largest to smallest. At any given time, I usually only care about the edges with the 3 largest values. There will only be a relatively small number of edges in the collection ranging from around 7 to 64. When I insert an edge, the values of the two adjacent edges will need to be adjusted. To do this, I will add the new edge to the set, then remove the two adjacent edges and re-add them with their new values. Can anyone share a more efficient data structure for this purpose?
#include <iostream>
#include <iomanip>
#include <sstream>
#include <set>
using namespace std;
struct Edge {
int maxlength;
int index;
Edge(int index, int maxlength) {
this->maxlength = maxlength;
this->index = index;
}
bool operator<(Edge other) const {
return maxlength < other.maxlength;
}
};
void run() {
set<Edge> edges;
edges.insert(Edge(25, 3));
edges.insert(Edge(21, 4));
edges.insert(Edge(28, 2));
cout << "First Edge: " << edges.begin()->maxlength << endl;
edges.erase(Edge(28, 2));
cout << "First Edge: " << edges.begin()->maxlength << endl;
edges.insert(Edge(39, 1));
cout << "First Edge: " << edges.begin()->maxlength << endl;
cout << "Last Edge: " << (--edges.end())->maxlength << endl;
}
int main() {
run();
return 1;
}
I've written a (array) container class template (lets call it smart array) for using it in the BREW platform (which doesn't allow many C++ constructs like STD library, exceptions, etc. It has a very minimal C++ runtime support); while writing this my friend said that something like this already exists in Boost called MultiArray, I tried it but the ARM compiler (RVCT) cries with 100s of errors. I've not seen Boost.MultiArray's source, I've started learning templates only lately; template meta programming interests me a lot, although am not sure if this is strictly one that can be categorized thus.
So I want all my fellow C++ aficionados to review it ~ point out flaws, potential bugs, suggestions, optimizations, etc.; something like "you've not written your own Big Three which might lead to...". Possibly any criticism that will help me improve this class and thereby my C++ skills.
Edit: I've used std::vector since it's easily understood, later it will be replaced by a custom written vector class template made to work in the BREW platform. Also C++0x related syntax like static_assert will also be removed in the final code.
smart_array.h
#include <vector>
#include <cassert>
#include <cstdarg>
using std::vector;
template <typename T, size_t N>
class smart_array
{
vector < smart_array<T, N - 1> > vec;
public:
explicit smart_array(vector <size_t> &dimensions)
{
assert(N == dimensions.size());
vector <size_t>::iterator it = ++dimensions.begin();
vector <size_t> dimensions_remaining(it, dimensions.end());
smart_array <T, N - 1> temp_smart_array(dimensions_remaining);
vec.assign(dimensions[0], temp_smart_array);
}
explicit smart_array(size_t dimension_1 = 1, ...)
{
static_assert(N > 0, "Error: smart_array expects 1 or more dimension(s)");
assert(dimension_1 > 1);
va_list dim_list;
vector <size_t> dimensions_remaining(N - 1);
va_start(dim_list, dimension_1);
for(size_t i = 0; i < N - 1; ++i)
{
size_t dimension_n = va_arg(dim_list, size_t);
assert(dimension_n > 0);
dimensions_remaining[i] = dimension_n;
}
va_end(dim_list);
smart_array <T, N - 1> temp_smart_array(dimensions_remaining);
vec.assign(dimension_1, temp_smart_array);
}
smart_array<T, N - 1>& operator[](size_t index)
{
assert(index < vec.size() && index >= 0);
return vec[index];
}
size_t length() const
{
return vec.size();
}
};
template<typename T>
class smart_array<T, 1>
{
vector <T> vec;
public:
explicit smart_array(vector <size_t> &dimension) : vec(dimension[0])
{
assert(dimension[0] > 0);
}
explicit smart_array(size_t dimension_1 = 1) : vec(dimension_1)
{
assert(dimension_1 > 0);
}
T& operator[](size_t index)
{
assert(index < vec.size() && index >= 0);
return vec[index];
}
size_t length()
{
return vec.size();
}
};
Sample Usage:
#include "smart_array.h"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
// testing 1 dimension
smart_array <int, 1> x(3);
x[0] = 0, x[1] = 1, x[2] = 2;
cout << "x.length(): " << x.length() << endl;
// testing 2 dimensions
smart_array <float, 2> y(2, 3);
y[0][0] = y[0][1] = y[0][2] = 0;
y[1][0] = y[1][1] = y[1][2] = 1;
cout << "y.length(): " << y.length() << endl;
cout << "y[0].length(): " << y[0].length() << endl;
// testing 3 dimensions
smart_array <char, 3> z(2, 4, 5);
cout << "z.length(): " << z.length() << endl;
cout << "z[0].length(): " << z[0].length() << endl;
cout << "z[0][0].length(): " << z[0][0].length() << endl;
z[0][0][4] = 'c'; cout << z[0][0][4] << endl;
// testing 4 dimensions
smart_array <bool, 4> r(2, 3, 4, 5);
cout << "r.length(): " << r.length() << endl;
cout << "r[0].length(): " << r[0].length() << endl;
cout << "r[0][0].length(): " << r[0][0].length() << endl;
cout << "r[0][0][0].length(): " << r[0][0][0].length() << endl;
// testing copy constructor
smart_array <float, 2> copy_y(y);
cout << "copy_y.length(): " << copy_y.length() << endl;
cout << "copy_x[0].length(): " << copy_y[0].length() << endl;
cout << copy_y[0][0] << "\t" << copy_y[1][0] << "\t" << copy_y[0][1] << "\t" <<
copy_y[1][1] << "\t" << copy_y[0][2] << "\t" << copy_y[1][2] << endl;
return 0;
}
If I'm understanding what you want from this type:
In short, it would be optimal to use the form:
template < typename T_, unsigned N_ >
struct t_array {
/* ... */
static const size_t Size = N_;
typedef T_ T;
T objects_[Size];
};
for many reasons if you want only a fixed size and fixed type array. The compiler can make a lot of safe assumptions - this has reduced object size to 20% (compared to using std::vector) for me in some cases. It also faster, safer. If you use them everywhere, then you may end up creating much larger binaries (compared to using std::vector).
There is a class <boost/array.hpp> which you should read.
Sorry if you don't find that helpful - I think reading at least one common production quality implementation (before venturing into new technologies) would help.