I want to create std::map with "T,int" but manually. I've copied std::set of data into clear vector, because I want to have an access to elements of unique elements. Here is a following code.
template<typename T>
void foo<T>::function()
{
std::set<T> unique_set(A.begin(), A.end());
std::copy(unique_set.begin(), unique_set.end(), std::inserter(vector_uniq, vector_uniq.begin()));
for (const auto&elem : vector_uniq)
{
counter = std::count(A.begin(), A.end(), elem); // declared in header as unsigned int
}
}
Is it possible to push value of counter to another vector ? Then I would have two vectors of value and their occurences and those two vectors will be used in another function. That's why I would like to have separated containers. Thank's for all responses.
Set up your second vector for the count results:
for (const auto&elem : vector_uniq) {
auto counter = std::count(A.begin(), A.end(), elem); // declared in header as unsigned int
vector_count.push_back(counter);
}
Related
I have already tried the below code but i want to use this same function for sorting based on different columns.
This given code is sorting based on first column only.
bool sortcol( const vector <int> v1, const vector <int> v2)
{
return v1[0]<v2[0];
}
sort(ArrOfTimings.begin(), ArrOfTimings.end(), sortcol);
Is there any way possible to not make multiple functions but making it all work with one only.
Something like this
bool sortcol(int ind, const vector <int> v1, const vector <int> v2)
{
return v1[ind]<v2[ind];
}
sort(ArrOfTimings.begin(), ArrOfTimings.end(), sortcol(0));
You cannot pass additional info to a free function used for comparison for std::sort by means other than global data.
You can create a struct with a member variable storing the column to compare in addition to providing a call operator for comparing the values though.
I'd prefer a lambda, since it results in shorter code though: Simply capture the index.
Note: It's also beneficial to avoid copying the vector by using references as parameters.
void SortByColumn(std::vector<std::vector<int>> & data, size_t column)
{
std::sort(data.begin(), data.end(),
[column](std::vector<int> const& v1, std::vector<int> const& v2)
{
return v1[column] < v2[column];
});
}
How, generally, can an stl algorithm be applied to a multidimensional vector (i.e. a vector<vector<T> >)?
For example, if I wanted to fill some vector, myVector, with values according to some function, myFunc(), I might use something like:
std::generate(myVector.begin() myVector.end(), myFunc())
Suppose now that myVec is a vector<vector<T> >. How might I use std::generate to populate every element of every vector in myVec according to myFunc? Need I use a loop (barring all other considerations)?
Would I simply write something like:
std::generate(myVec.begin(), myVec.end(), std::generate(...))
Surprisingly, I cannot find anything on this here or elsewhere.
The generator passed to std::generate() needs to return a type that is assignable to the element type of the container. So, in your example, the element type of myVector is another vector, so myFunc() would need to return a whole vector, eg:
template<typename T>
vector<T> myFunc()
{
vector<T> v;
// populate v as needed...
return v;
}
vector<vector<T> > myVector(some size);
std::generate(myVector.begin() myVector.end(), myFunc<T>);
Otherwise, you will have to do something more like this instead:
template<typename T>
void myFunc(vector<T> &v)
{
// populate v as needed...
}
vector<vector<T>> myVector(some size);
for(auto &v : myVector) {
myFunc(v);
}
With range library (as range-v3), you might flatten your vectors to work with vector of less dimension:
std::vector<std::vector<int>> v(4, std::vector<int>(3));
auto flattened = v | ranges::view::join;
std::generate(begin(flattened), end(flattened), [n = 0]() mutable{ return n++; });
Demo
Else, regular loop seems the simpler:
auto gen = [n = 0]() mutable{ return n++; }
for (auto& inner : v) {
std::generate(begin(inner), end(inner), gen);
}
You cannot really nest generate calls as it doesn't take current element to know size of each inner vector.
I have a vector of elements std::vector<T> my_vec. At some point in my code I assign a score for each element of the vector using an unordered map. After that, I would like to sort the vector by the scores of its elements with the minimum code possible.
I came up with this solution, define the map as follows: std::unordered_map<const T*, float> scores_map. For score assignment, insert the score to the map as follows:
for (const auto& el : my_vec)
scores_map[&el] = calc_score(el);
Then I sort using:
std::sort(my_vec.begin(), my_vec.end(),
[&my_map](const auto& a, const auto& b){return my_map[&a] > my_map[&b];});
Is this considered a bug-free and good practice, if not any idea how to make it so?
#fas wrote in a comment:
Elements in vector are moved during sort, so their pointers also change and scores_map becomes invalid, isn't it?
That is correct. You should not use pointers as keys in scores_map.
Option 1
If the vector contains unique items, you may use the T as the key type.
for (const auto& el : my_vec)
scores_map[el] = calc_score(el);
Then sort using:
std::sort(my_vec.begin(), my_vec.end(),
[&my_map](const auto& a, const auto& b){return my_map[a] > my_map[b];});
Option 2
If the vector does not contain unique elements, you may use the following strategy.
Use indices as the key of my_map.
Create a helper std::vector<size_t> object that contains just indices.
Sort the vector of indices.
Use the sorted indices vector to fetch the elements from my_vec.
for (size_t i = 0; i < my_vec.size(); ++i )
scores_map[i] = calc_score(my_vec[i]);
// Create the vector of indices
std::vector<size_t> indices_vec(my_vec.size());
for ( size_t i = 0; i < indices_vec.size(); ++i )
{
indices_vec[i] = i;
}
// Sort the vector of indices
std::sort(indices_vec.begin(), indices_vec.end(),
[&my_map](size_t a, size_t b){return my_map[a] > my_map[b];});
for (auto index : indices_vec)
{
// Use my_vec[index]
}
No, this not bug-free. std::sort will change the addresses of the elements.
You could store the score with each element in a pair:
std::pair<float, T>
and sort the vector
std::vector<std::pair<float, T> > my_vec
with
std::sort(my_vec.begin(), my_vec.end(),
[](const auto& a, const auto& b){return a.first > b.first;});
What is the best way to return only the unique element with the counts from vector of vectors?
std::vector<std::vector<string>> vec_vec{{a,a,b,c},{a,c,c}};
The results should be :
{a, b, c} // This is the vector that contains the unique items.
{3, 1, 3} //a exists three times, b only one time, and c is three times.
To solve this I use the following:
1- Copy all the items in the vector of vector to single vector, so the output will be:
vec_vec{{a,a,b,c},{a,c,c}} -> vec{a,a,b,c,a,c,c}
2- Now I'm dealing with a single vector (not vector of vector), so it's much easier to sort, get the unique items and them (I may use the code here1 and here2)
Is converting the vector of vector to one vector is a good idea? Any better solution?
Can we find better way with less complexity comparing with the current way (c++11, c++14)?
From the top of my mind:
std::unordered_map<std::string, std::size_t> counters;
for(auto const& inner : vec_vec)
for(auto const& v : inner)
counters[v]++;
for(auto const& cnt : counters)
std::cout << cnt.first << " appears " << cnt.second << std::endl;
Use hash maps.
std::unordered_map<string, int> result;
for (const auto& x : vec_vec)
for (const string& y : x)
result[y]++;
I would just use a map as "tally" structure:
std::map<string, unsigned int> tally;
for(auto subvector : vector) { // subvector is std::vector<std::string>
for(auto item : subvector) { // item is a std::string
++tally[item];
}
}
If you insist on having the result as two parallel vectors (but why would you?) simply construct them from the map:
std::vector<std::string> unique_items;
unique_items.reserve(tally.size());
std::vector<unsigned int> counts;
counts.reserve(tally.size());
for(auto item : tally) {
unique_items.push_back(item.first);
counts.push_back(item.second);
}
If you don't want the result vector to be sorted, you can use an unordered_map, as suggested in other answers.
How shall I use the qsort function to sort a set of pairs ?
This is my set :
set< pair< int, int> > my_set
This I guess should be my compare function:
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
Should my qsort look like this?
qsort (my_set, no_of_pairs, sizeof(int), compare);
When I sort them I want to sort by the values of a bi-dimensional array **M;, where
M[my_set.first][my_set.second] = the_value
First, prefer std::sort to qsort with c++ std containers.
Secondly, you cannot sort a std::set a posteriori. std::set is sorted.
You can however specify a custom sorting for the std::set at instanciation using a 2nd template parameter.
Refer to the specs.
What you could do, if you need to sort the data after the fact, is use a std::vector instead. There is an algorithm that will cull the duplicate value.
This proposed solution assumes M is some global variable.
#include <algorithm>
bool less_than(const std::pair<int, int> &some, const std::pair<int, int> &other) {
return M[some.first][some.second] < M[other.first][other.second];
}
std::sort(yourvector.begin(), yourvector.end(), less_than);
If M isn't a global variable, you could do something like that :
struc Compair { // see what I did there ? #sofunny
bool operator() (const std::pair<int, int> &some, const std::pair<int, int> &other) {
return M[some.first][some.second] < M[other.first][other.second];
}
int **M;
}
then in main :
Compair mycomparefunctor;
mycomparefunctor.M = arr; // arr is the original int **
std::sort(yourvector.begin(), yourvector.end(), mycomparefunctor);
EDIT :
If you must use a std::set then you should define the custom ordering when you declare it, like so :
Compair mypredicate;
mypredicate.M = arr; // arr is the original int **
std::set<std::pair<int, int>, mypredicate> myset;
// add stuff to the set. They will be sorted following your predicate.
Be careful though : in a set you cannot add 2 items that compare equal. So if your int ** 2D array has several values that are equal, you won't be able to have several pairs corresponding to indexes of equal value in the set.
You're going about this fairly wrong.
Let's assume that we know the maximum value for each member of the pair. If you don't know this, then you need to figure it out. I'm going to assume that it is 100.
Then all we need to do is iterate over the set, and insert them into the new array. There's no faster way to go about this.
int M[100][100] = {};
for (auto const & pair : my_set)
M[pair.first][pair.second] = the_value;