I'm trying write a tempate function which takes a sequence (by 2 iterators) and calculates the number of permutations of this sequence, in which there are no consecutive identical elements.
Thats what i did
template<class Iterator>
size_t count_perm(Iterator p, Iterator q)
{
if (p == q)
return 1;
size_t count = 0;
while(std::next_permutation(p, q)){
if(std::adjacent_find(p,q) != q)
++count;
}
}
/*Example
std::array<int, 3> a1 = {1,2,3};
size_t c1 = count_perm(a1.begin(), a1.end()); // 6
std::array<int, 5> a2 = {1,2,3,4,4};
size_t c2 = count_perm(a2.begin(), a2.end()); // 36*/
This code not working if i pass const iterators. What should I change to make it work with const iterators?
This code not working if i pass const iterators. What should I change to make it work with const iterators?
You can't: std::next_permutation() modify the values so is incompatible with const iterators.
-- EDIT --
The OP ask
How can i implement this function in right way?
I suggest you to follows the suggestion from Jarod42: works over a copy.
I propose something as follows
template <class Container>
size_t count_perm (Container c) // note: c is a copy
{
if ( c.cbegin() == c.cend() )
return 1;
size_t count = 0U;
std::sort(c.begin(), c.end());
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend()))
{
std::size_t ui = c.size();
for ( count = ui ; --ui > 1 ; count *= ui )
;
// count now is c.size() ! (factorial of)
}
else
{
while (std::next_permutation(c.begin(), c.end()))
if (std::adjacent_find(c.cbegin(), c.cend()) != c.cend())
++count;
}
return count; // remember this return!
}
Fixed your templated function for you (still requires non-const iterators):
template<class Iterator> size_t count_perm(Iterator p, Iterator q)
{
if (p == q || std::all_of(p, q, [&](auto &el) {return el == *p; })))
return 0;
size_t count = 1;
std::sort(p, q);
while (std::next_permutation(p, q))
if (std::adjacent_find(p, q) == q)
++count;
return count;
}
you should return count
when no adjacent elements are found, std::adjacent_find returns end, so you should == q not != q
Your example produces 6 and 37. Should it be 36 instead of 37?
Solved this exercise as follows, it works with const iterators:
template<class Iterator>
size_t count_permutations(Iterator p, Iterator q)
{
using T = typename std::iterator_traits<Iterator>::value_type;
if (p == q)
return 1;
std::vector<T> v(p,q);
std::sort(v.begin(), v.end());
size_t count = 0;
do{
if(std::adjacent_find(v.begin(),v.end()) == v.end()) {
++count;
}
} while(std::next_permutation(v.begin(), v.end()));
return count;
}
Problem was to use std::type_traits<Iterator>::value_type instead Iterator::value_type (that not working with const iters and simple pointers (like int*))
Related
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
For example, suppose I have two vectors of the same size:
vector<MyObject> vectorA;
vector<int> vectorB;
I then sort vectorA using some comparison function. That sorting reordered vectorA. How can I have the same reordering applied to vectorB?
One option is to create a struct:
struct ExampleStruct {
MyObject mo;
int i;
};
and then sort a vector that contains the contents of vectorA and vectorB zipped up into a single vector:
// vectorC[i] is vectorA[i] and vectorB[i] combined
vector<ExampleStruct> vectorC;
This doesn't seem like an ideal solution. Are there other options, especially in C++11?
Finding a sort permutation
Given a std::vector<T> and a comparison for T's, we want to be able to find the permutation you would use if you were to sort the vector using this comparison.
template <typename T, typename Compare>
std::vector<std::size_t> sort_permutation(
const std::vector<T>& vec,
Compare& compare)
{
std::vector<std::size_t> p(vec.size());
std::iota(p.begin(), p.end(), 0);
std::sort(p.begin(), p.end(),
[&](std::size_t i, std::size_t j){ return compare(vec[i], vec[j]); });
return p;
}
Applying a sort permutation
Given a std::vector<T> and a permutation, we want to be able to build a new std::vector<T> that is reordered according to the permutation.
template <typename T>
std::vector<T> apply_permutation(
const std::vector<T>& vec,
const std::vector<std::size_t>& p)
{
std::vector<T> sorted_vec(vec.size());
std::transform(p.begin(), p.end(), sorted_vec.begin(),
[&](std::size_t i){ return vec[i]; });
return sorted_vec;
}
You could of course modify apply_permutation to mutate the vector you give it rather than returning a new sorted copy. This approach is still linear time complexity and uses one bit per item in your vector. Theoretically, it's still linear space complexity; but, in practice, when sizeof(T) is large the reduction in memory usage can be dramatic. (See details)
template <typename T>
void apply_permutation_in_place(
std::vector<T>& vec,
const std::vector<std::size_t>& p)
{
std::vector<bool> done(vec.size());
for (std::size_t i = 0; i < vec.size(); ++i)
{
if (done[i])
{
continue;
}
done[i] = true;
std::size_t prev_j = i;
std::size_t j = p[i];
while (i != j)
{
std::swap(vec[prev_j], vec[j]);
done[j] = true;
prev_j = j;
j = p[j];
}
}
}
Example
vector<MyObject> vectorA;
vector<int> vectorB;
auto p = sort_permutation(vectorA,
[](T const& a, T const& b){ /*some comparison*/ });
vectorA = apply_permutation(vectorA, p);
vectorB = apply_permutation(vectorB, p);
Resources
std::vector
std::iota
std::sort
std::swap
std::transform
With range-v3, it is simple, sort a zip view:
std::vector<MyObject> vectorA = /*..*/;
std::vector<int> vectorB = /*..*/;
ranges::v3::sort(ranges::view::zip(vectorA, vectorB));
or explicitly use projection:
ranges::v3::sort(ranges::view::zip(vectorA, vectorB),
std::less<>{},
[](const auto& t) -> decltype(auto) { return std::get<0>(t); });
Demo
I would like to contribute with a extension I came up with.
The goal is to be able to sort multiple vectors at the same time using a simple syntax.
sortVectorsAscending(criteriaVec, vec1, vec2, ...)
The algorithm is the same as the one Timothy proposed but using variadic templates, so we can sort multiple vectors of arbitrary types at the same time.
Here's the code snippet:
template <typename T, typename Compare>
void getSortPermutation(
std::vector<unsigned>& out,
const std::vector<T>& v,
Compare compare = std::less<T>())
{
out.resize(v.size());
std::iota(out.begin(), out.end(), 0);
std::sort(out.begin(), out.end(),
[&](unsigned i, unsigned j){ return compare(v[i], v[j]); });
}
template <typename T>
void applyPermutation(
const std::vector<unsigned>& order,
std::vector<T>& t)
{
assert(order.size() == t.size());
std::vector<T> st(t.size());
for(unsigned i=0; i<t.size(); i++)
{
st[i] = t[order[i]];
}
t = st;
}
template <typename T, typename... S>
void applyPermutation(
const std::vector<unsigned>& order,
std::vector<T>& t,
std::vector<S>&... s)
{
applyPermutation(order, t);
applyPermutation(order, s...);
}
template<typename T, typename Compare, typename... SS>
void sortVectors(
const std::vector<T>& t,
Compare comp,
std::vector<SS>&... ss)
{
std::vector<unsigned> order;
getSortPermutation(order, t, comp);
applyPermutation(order, ss...);
}
// make less verbose for the usual ascending order
template<typename T, typename... SS>
void sortVectorsAscending(
const std::vector<T>& t,
std::vector<SS>&... ss)
{
sortVectors(t, std::less<T>(), ss...);
}
Test it in Ideone.
I explain this a little bit better in this blog post.
In-place sorting using permutation
I would use a permutation like Timothy, although if your data is too large and you don't want to allocate more memory for the sorted vector you should do it in-place. Here is a example of a O(n) (linear complexity) in-place sorting using permutation:
The trick is to get the permutation and the reverse permutation to know where to put the data overwritten by the last sorting step.
template <class K, class T>
void sortByKey(K * keys, T * data, size_t size){
std::vector<size_t> p(size,0);
std::vector<size_t> rp(size);
std::vector<bool> sorted(size, false);
size_t i = 0;
// Sort
std::iota(p.begin(), p.end(), 0);
std::sort(p.begin(), p.end(),
[&](size_t i, size_t j){ return keys[i] < keys[j]; });
// ----------- Apply permutation in-place ---------- //
// Get reverse permutation item>position
for (i = 0; i < size; ++i){
rp[p[i]] = i;
}
i = 0;
K savedKey;
T savedData;
while ( i < size){
size_t pos = i;
// Save This element;
if ( ! sorted[pos] ){
savedKey = keys[p[pos]];
savedData = data[p[pos]];
}
while ( ! sorted[pos] ){
// Hold item to be replaced
K heldKey = keys[pos];
T heldData = data[pos];
// Save where it should go
size_t heldPos = rp[pos];
// Replace
keys[pos] = savedKey;
data[pos] = savedData;
// Get last item to be the pivot
savedKey = heldKey;
savedData = heldData;
// Mark this item as sorted
sorted[pos] = true;
// Go to the held item proper location
pos = heldPos;
}
++i;
}
}
I have recently wrote a proper zip iterator which works with the stl algorithms.
It allows you to produce code like this:
std::vector<int> a{3,1,4,2};
std::vector<std::string> b{"Alice","Bob","Charles","David"};
auto zip = Zip(a,b);
std::sort(zip.begin(), zip.end());
for (const auto & z: zip) std::cout << z << std::endl;
It is contained in a single header and the only requirement is C++17.
Check it out on GitHub.
There is also a post on codereview which contains all the source code.
Make a vector of pairs out of your individual vectors.
initialize vector of pairs
Adding to a vector of pair
Make a custom sort comparator:
Sorting a vector of custom objects
http://rosettacode.org/wiki/Sort_using_a_custom_comparator#C.2B.2B
Sort your vector of pairs.
Separate your vector of pairs into individual vectors.
Put all of these into a function.
Code:
std::vector<MyObject> vectorA;
std::vector<int> vectorB;
struct less_than_int
{
inline bool operator() (const std::pair<MyObject,int>& a, const std::pair<MyObject,int>& b)
{
return (a.second < b.second);
}
};
sortVecPair(vectorA, vectorB, less_than_int());
// make sure vectorA and vectorB are of the same size, before calling function
template <typename T, typename R, typename Compare>
sortVecPair(std::vector<T>& vecA, std::vector<R>& vecB, Compare cmp)
{
std::vector<pair<T,R>> vecC;
vecC.reserve(vecA.size());
for(int i=0; i<vecA.size(); i++)
{
vecC.push_back(std::make_pair(vecA[i],vecB[i]);
}
std::sort(vecC.begin(), vecC.end(), cmp);
vecA.clear();
vecB.clear();
vecA.reserve(vecC.size());
vecB.reserve(vecC.size());
for(int i=0; i<vecC.size(); i++)
{
vecA.push_back(vecC[i].first);
vecB.push_back(vecC[i].second);
}
}
I'm assuming that vectorA and vectorB have equal lengths. You could create another vector, let's call it pos, where:
pos[i] = the position of vectorA[i] after sorting phase
and then, you can sort vectorB using pos, i.e create vectorBsorted where:
vectorBsorted[pos[i]] = vectorB[i]
and then vectorBsorted is sorted by the same permutation of indexes as vectorA is.
I am not sure if this works but i would use something like this. For example to sort two vectors i would use descending bubble sort method and vector pairs.
For descending bubble sort, i would create a function that requires a vector pair.
void bubbleSort(vector< pair<MyObject,int> >& a)
{
bool swapp = true;
while (swapp) {
int key;
MyObject temp_obj;
swapp = false;
for (size_t i = 0; i < a.size() - 1; i++) {
if (a[i].first < a[i + 1].first) {
temp_obj = a[i].first;
key = a[i].second;
a[i].first = a[i + 1].first;
a[i + 1].first = temp_obj;
a[i].second = a[i + 1].second;
a[i + 1].second = key;
swapp = true;
}
}
}
}
After that i would put your 2 vector values into one vector pair. If you are able to add values at the same time use this one and than call the bubble sort function.
vector< pair<MyObject,int> > my_vector;
my_vector.push_back( pair<MyObject,int> (object_value,int_value));
bubbleSort(my_vector);
If you want to use values after adding to your 2 vectors, you can use this one and than call the bubble sort function.
vector< pair<MyObject,int> > temp_vector;
for (size_t i = 0; i < vectorA.size(); i++) {
temp_vector.push_back(pair<MyObject,int> (vectorA[i],vectorB[i]));
}
bubbleSort(temp_vector);
I hope this helps.
Regards,
Caner
Based on Timothy Shields answer.
With a small tweak to apply_permutaion you can apply the permutation to multiple vectors of different types at once with use of a fold expression.
template <typename T, typename... Ts>
void apply_permutation(const std::vector<size_t>& perm, std::vector<T>& v, std::vector<Ts>&... vs) {
std::vector<bool> done(v.size());
for(size_t i = 0; i < v.size(); ++i) {
if(done[i]) continue;
done[i] = true;
size_t prev = i;
size_t curr = perm[i];
while(i != curr) {
std::swap(v[prev], v[curr]);
(std::swap(vs[prev], vs[curr]), ...);
done[curr] = true;
prev = curr;
curr = perm[curr];
}
}
}
I need to remove the elements that appear in Vector A and Vector B, but keep the elements that are only in Vector A. The vectors can be of any size, but are not necessarily equal to each other.
For example, if:
vector A contains the values <1,4,66,22>
vector B contains the values <1,22,44,93,102,543>
Then after preforming the operation:
vector A should contain <4,66>
vector B should contain <44,93,102,543>
Do I need to loop through both with a for loop and strncmp the values or is the a function that I can use to streamline the process?
This is what I tried but doesn't seem to work.
string rawInput;
string fileInput;
vector<string> stdInput; //vector to hold standard input values
vector<string> fileList; //vector to hold file values
sizeIn = stdInput.size();
sizeFile = fileList.size();
if (sizeIn >= sizeFile)
{
for (count = 0;count <= sizeIn; count++)
{
for (count1 = 0; count1 <= sizeFile; count1++)
{
if (stdInput[count1] == fileList[count])
{
stdInput.erase(stdInput.begin()+count1-1);
fileList.erase(fileList.begin()+count-1);
}
}
}
}
else
{
for (count = 0; count <= sizeFile; count ++)
{
for (count1 = 0; count1 <= sizeIn; count1++)
{
if (stdInput[count] == fileList[count1])
{
stdInput.erase(stdInput.begin()+count-1);
fileList.erase(fileList.begin()+count1-1);
}
}
}
}
That's a lot of work there. I would have suggested std::set_difference, but since you want to do it in place, this code will do it for you with good algorithmic complexity:
template<typename T>
void remove_intersection(std::vector<T>& a, std::vector<T>& b){
std::unordered_multiset<T> st;
st.insert(a.begin(), a.end());
st.insert(b.begin(), b.end());
auto predicate = [&st](const T& k){ return st.count(k) > 1; };
a.erase(std::remove_if(a.begin(), a.end(), predicate), a.end());
b.erase(std::remove_if(b.begin(), b.end(), predicate), b.end());
}
Isn't C++ beautiful? :-)
A Demo:
int main(){
std::vector<int> a = {1,4,66,22};
std::vector<int> b = {1,22,44,93,102,543};
remove_intersection(a, b);
for(auto k : a) std::cout << k << ' ';
std::cout << std::endl;
for(auto k : b) std::cout << k << ' ';
}
Outputs:
4 66
44 93 102 543
See it Live On Coliru
There are many variations of the above method. For example, if you are worried that count may take too long when such count is really large, you can implement a simple function to find and count up to at most 2 elements; another one: you can simply use two different unordered sets.
No, I will resort them via sort(fileList.begin(), fileList.end() ); after
So asymptotically it's the same to sort before.
Using set_difference, you can do something like:
template<typename T>
void remove_intersection(std::vector<T>* c1, std::vector<T>* c2) {
assert(c1 != nullptr);
assert(c2 != nullptr);
std::sort(std::begin(*c1), std::end(*c1)); // O(n1 logn1)
std::sort(std::begin(*c2), std::end(*c2)); // O(n2 logn2)
std::vector<T> difference1, difference2;
difference1.reserve(c1->size());
difference2.reserve(c2->size());
std::set_difference(std::begin(*c1), std::end(*c1),
std::begin(*c2), std::end(*c2),
std::back_inserter(difference1));
// O(2*[N1 + N2 - 1])
std::set_difference(std::begin(*c2), std::end(*c2),
std::begin(*c1), std::end(*c1),
std::back_inserter(difference2));
// O(2*[N1 + N2 - 1])
*c1 = std::move(difference1); // O(1)
*c2 = std::move(difference2); // O(1)
}
Thanks to #WhiZTiM for the great code example.
For my application it had some issues:
only applicable to vectors
removes duplicates from a although they are not in b
does not pay attention to const correctness
This suggested variation deals with those issues.
template <typename ContainerT>
void remove_intersection(ContainerT& a, ContainerT& b)
{
std::unordered_set<ContainerT::value_type> const uniqueAs { a.cbegin(), a.cend() };
std::unordered_multiset<ContainerT::value_type> st { uniqueAs.cbegin(), uniqueAs.cend() };
st.insert(b.begin(), b.end());
auto const predicate = [&st](ContainerT::value_type const& k) { return st.count(k) > 1; };
a.erase(std::remove_if(a.begin(), a.end(), predicate), a.cend());
b.erase(std::remove_if(b.begin(), b.end(), predicate), b.cend());
}
I might try something like the following.
// Create sets from vectors. This eliminates the duplicate elements.
const unordered_set<int> setA{vecA.cbegin(), vecA.cend()};
const unordered_set<int> setB{vecB.cbegin(), vecB.cend()};
PopulateSetDiff(vecA, setA, setB);
PopulateSetDiff(vecB, setB, setA);
// Populate 'vec' with 'set1 - set2'
template <typename T>
void PopulateSetDiff(
vector<T>& vec,
unordered_set<T> const& set1,
unordered_set<T> const& set2) {
vec.clear();
for (const auto elem : set1) {
if (set2.find(elem) == set2.cend()) {
vec.push_back(elem);
}
}
vec.shrink_to_fit();
}
for (auto& d : deleteCommands) {
auto it = stackCommands.begin();
while (it != stackCommands.end()) {
if (d == *it._Ptr) {
commands[d]->Exit(this);
it = stackCommands.erase(it);
}
else { it++; }
}
}
This code:
for (std::list<point>::const_iterator it = controlPoints->begin();
it != controlPoints->end();
++it) {
...
}
Corresponds to:
for (int i = 0; i < controlPoints->size; i++) {
...
}
Meaning, it would iterate through all elements of the list if I got one element for each time it looped.
What would correspond to:
for (int i = 0; i < controlPoints->size-1; i++) {
...
}
I mean, how can I loop size-1 times using iterators?
The obvious way would be to get an iterator to the end and decrement it:
auto stop = controlPoints.end();
--stop;
for (std::list<point>::const_iterator it = controlPoints->begin();
it != stop;
++it) {
...
}
You could use std::advance or std::next if you preferred, but for this case a simple decrement is fine.
controlPoints->end() is also an iterator.
You could do this:
std::list<point>::const_iterator it = controlPoints->begin();
std::list<point>::const_iterator stop = controlPoints->end();
if ( it != stop) for ( --stop; it != stop; ++it) {
...
}
More verbose but it's safe to use whether the list has 0, 1 or more elements.
The key here is that iterators can be incremented and (for bidirectional iterators) decremented to advance / recede the position, so it's the equivalent of doing:
int it = 0;
int stop = list.size();
if (it != stop) for( --stop; it < stop; ++it ) {
...
}
In C++11 you should seek to use the ranged based for loop as often as you can. for(;;) loops are complex and error prone at the point you write them.
Using for(:) loops requires complexity away from the point you write them, but because you can write that infrastructure once and reuse it the bugs in it can be ironed out, instead of being dispursed throughout the code.
To start with, here is a simple range_t:
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
std::size_t size() const { return std::distance(begin(), end()); }
using iterator_tag = typename std::iterator_traits<It>::iterator_category;
private:
static It safe_advance( It in, It bound, std::ptrdiff_t n, std::random_access_iterator_tag ) const {
if (n == 0) return in;
if (n < 0) n = (std::min)( n, -std::distance( bound, in ) );
if (n > 0) n = (std::max)( n, std::distance( in, bound ) );
return std::advance( in, n );
}
static It safe_advance( It in, It bound, std::ptrdiff_t n, ... ) const {
if (n == 0) return in;
while (n < 0 && in != bound) {
in = std::prev(in); --n;
}
while (n > 0 && in != bound) {
in = std::next(in); ++n;
}
return in;
}
public:
range_t without_back( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), -(std::ptrdiff_t)n, iterator_tag{} };
}
range_t without_front( std::size_t n = 1 ) const {
return {begin(), safe_advance( end(), begin(), n, iterator_tag{} };
}
bool empty() const { return begin() == end(); }
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
};
template<class It>
range_t<It> range( It b, It e ) { return {b,e}; }
// rvalues blocked:
template<class C, class It = decltype( std::begin(std::declval<C&>()) )>
range_t<It> range( C& c ) { return range( std::begin(c), std::end(c) ); }
it stores a range of iterators and is itself iterable.
Then:
auto r = range(*controlPoints).without_back();
is a range object that is the controlPoints without the last element.
Using ranged-based for you can do this:
for (auto& x : range(*controlPoints).without_back()) {
}
note that the above code carefully handles being fed an empty array.
We can also write a similar adapter that lets you iterator over the iterators. I usually do this by writing an index_iterator that stores an Index and passes ++ and == etc to it. Except when you * it simply returns a copy of the Index.
This is useful to create an iterator over integers, but also lets you create an iterator over iterators.
Then create a range of indexes to the iterators in your container, and you get syntax that looks like:
for (auto it : iterators_into( *controlPoints) ) {
}
giving you range-based loops that also gives you iterators if you need them.
I had this on an interview question. I'd like to see how StackOverflow would do it.
What would Bjarne Stroustrop think of my way? It's a little wordy, but I don't know how to make it better, unfortunately. I know you guys are gonna laugh at my stupidity.
template <class T>
T mode(T* arr, size_t n)
// If there's a tie, return an arbitrary element tied for 1st
// If the array size is 0, throw an error
{
if (n == 0)
{
throw("Mode of array of size 0 is undefined, bro.");
}
else if (n == 1)
{
return arr[0];
}
else
{
std::pair<T, int> highest(arr[0], 1);
std::map<T, int> S;
S.insert(highest);
for (T* thisPtr(arr + 1), lastPtr(arr+n); thisPtr != lastPtr; ++thisPtr)
{
if (S.count(*thisPtr) == 0)
{
S.insert(std::pair<T, int> (*thisPtr, 1);
}
else
{
++S[*thisPtr];
if (S[*thisPtr] > highest.second)
{
highest = std::pair<T, int> (*thisPtr, S[*thisPtr]);
}
}
}
}
}
You could do this, provided that T implements std::hash:
std::unordered_multiset<T> elems;
std::for_each(arr, arr + size, [&elems](T const & elem) { elems.insert(elem); }
//Now you have elems.count() for each entry
auto max_count = /*Guaranteed minimum value*/
T mode{};
for (auto const & set_elem : elems) {
if (max(elems.count(set_elem), max_count) == max_count)) {
mode = set_elem;
}
}
I think I'd use an std::map to do the counting, then find the item with the largest count:
template <class T>
T mode(T* arr, size_t n) {
std::map<T, size_t> counts;
for (size_t i=0; i<n; i++)
++counts[arr[i]];
return max_element(counts.begin(), counts.end(),
[](std::pair<T, size_t> const &a, std::pair<T, size_t> const &b) {
return a.second < b.second;
})->first;
}
If you expect a really large number of unique items, you might want to use an std::unordered_map instead of a std::map [should reduce expected complexity from O(n log n) to O(N)].
I found the following issues with your code.
Redundant check n == 1
You can remove the block
else if (n == 1)
{
return arr[0];
}
without affecting the outcome.
Declaration of the variables in the for loop:
T* thisPtr(arr + 1), lastPtr(arr+n);`
is equivalent to
T* thisPtr(arr + 10); T lastPtr(arr+n);
That's not what your intention is. The compiler will report an error too. So, move their declaration outside the for loop. Change
for (T* thisPtr(arr + 1), lastPtr(arr+n); thisPtr != lastPtr; ++thisPtr)
to
T* thisPtr(arr + 1);
T* lastPtr(arr+n);
for ( ; thisPtr != lastPtr; ++thisPtr)
Simplify the contents of the for loop
The lines
if (S.count(*thisPtr) == 0)
{
S.insert(std::pair<T, int> (*thisPtr, 1));
}
can be replaced by
++S[*thisPtr];
which is exactly what you are doing in the following else block.
You can change the contents of the entire for loop to:
++S[*thisPtr];
if (S[*thisPtr] > highest.second)
{
highest = std::pair<T, int> (*thisPtr, S[*thisPtr]);
}
You need to return the mode
Add
return highest.first;
before the closing of the else block.
I'm wondering: is there any possibility to add additional condition to for each?
I'm thinking about something like:
int i=0;
for(auto &it : list; i++)
if(it.ID == 25)
return i;
or
for(auto &it : list, int i=0; i++)
if(it.ID == 25)
return i;
You can use std::find_if:
const auto position = std::find_if(list.cbegin(), list.cend(), []((decltype(*list.cbegin()) value)
{
return value.ID == 25;
});
return position - list.cbegin();
(Updated, now independent of container value_type)
No it's not possible. You can use the old "normal" for loop for that:
auto iter = std:begin(list)
for (int i = 0; iter != std::end(list); ++iter, ++i)
{
auto& it = *iter;
// ...
}
Mandatory Reference: Sean Parent's "Seasoning C++" talk:
goal 1: Avoid raw loops
In cases like these, abstract your algorithm!
This will come up more often, so it's worth making it generic:
#include <algorithm>
template <typename C, typename Pred>
size_t index_if(C const& c, Pred&& pred)
{
const auto f(begin(c)), l(end(c));
auto match = std::find_if(f, l, std::forward<Pred>(pred));
return (l==match) ? -1 : std::distance(f, match);
}
Now you can write your query:
int main()
{
struct X { int ID; };
const std::vector<X> v { {1},{2},{3},{25},{4},{5},{6},{42} };
return index_if(v, [](X const& x) { return x.ID == 25; });
}
See it Live on Coliru
PS. You might want a value-based version along with the predicate-based one:
template <typename C, typename V/* = typename C::value_type*/>
size_t index_of(C const& c, V const v)
{
const auto f(begin(c)), l(end(c));
auto match = std::find(f, l, v);
return (l==match) ? -1 : std::distance(f, match);
}