Detect equal elements in a std::list - c++

Is there a better way of finding elements of a std::list that have the same value as manually going over the sorted list and comparing each element like this:
for(auto it = l.begin(); it != l.end(); it++) {
auto nextElement = it;
nextElement++;
if(nextElement == l.end())
break;
if(*it == *nextElement)
cout << "Equal" << endl;
}

There is actually a really nice and compact way to get a list of all of the duplicates in a set of data, whether it is sorted or not. What we can do is leverage std::map/std::unordered_map and use the elements value as the key for the map, and make the value a count of the number of times that value was "inserted". That would look like
std::unordered_map<int, int> histogram;
for (auto e : l)
++histogram[e]; // gets a count of the number of duplicates
and then all you need to do is iterate the map and check for entries that have a mapped value greater than 1. That would look like
for (const auto& pair : histogram)
if (pair.second > 1)
std::cout << "value: " << pair.first << " has " << pair.second << " matches.\n";
Using a std::map this is O(NlogN + M) and using an unoredered_map this is O(N + M) where N is the size of l and M is the size of histogram.

Use the STL algorithm adjacent_find:
auto it = l.begin()
while((it = std::adjacent_find(it, l.end())) != l.end()){
std::cout << "Equal\n";
++it;
}

Since you say the list is sorted, then std::adjacent_find will detect whether there are duplicates:
#include <algorithm>
if (std::adjacent_find(l.begin(), l.end()) != l.end()) {
// we have at least one duplicate
}
If you wish to do something with all the duplicates, then we can loop over the pairs:
for (auto it = std::adjacent_find(l.begin(), l.end());
it != l.end();
it = std::adjacent_find(std::next(it), l.end())
{
// *it and *std::next are duplicates (and there may be more)
}
It's possible that we want to find and process all of each group of identical elements together:
auto begin = std::adjacent_find(l.begin(), l.end());
while (begin != l.end()) {
auto end = std::find_if_not(begin, l.end(),
[begin](auto n){ return n == *begin;});
// All elements from begin (inclusive) to end (exclusive) are equal.
// Process them here.
begin = std::adjacent_find(end, l.end());
}

Related

Why the std::map storing fewer elements than expected?

Why the map in my code is storing only two elements instead of three?
vector<int> v1 = { 140,229,319 };
vector<int> v2 = { 82,216,326 };
map<int, int> mp;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] > v2[i])
{
mp.insert({ 1,v1[i] - v2[i] });
}
else if (v2[i] > v1[i])
{
mp.insert({ 2,v2[i] - v1[i] });
}
}
cout << mp.size() << endl;
for (auto it = mp.begin(); it != mp.end(); it++)
{
cout << it->first << " " << it->second << endl;
}
It should store: (1,58) (1,13) (2,7)ideally. But it is storing only (1,58) (2,7). I checked the size and it was showing 2.
Where am I going wrong?
First, std::mapis a sorted associative container, which only keeps unique keys. Meaning, what you're expecting is not possible with the std::map.
You should think either with
std::multimap(sorted list of key-value pairs),
std::vector<std::pair<int, int>>(unsorted list of key-value pairs) etc here, so that the multiple keys should not be an issue.
Where am I going wrong?
Consider the check
if(v1[i] > v2[i])
you have two iteration which satisfy this condition:
140, 229 // v1
82 , 216 // v2
The difference (i.e. v1[index] - v2[index]) between the first two is 58 and the second is 13.
In the first iteration, the map get inserted with the (1, 58). In the second iteration it should have (1, 13), but from std::map::insert:
Inserts element(s) into the container, if the container doesn't
already contain an element with an equivalent key.
Hence it has not been inserted.

Sorted element container which can be accessed by index [duplicate]

I have a set of type set<int> and I want to get an iterator to someplace that is not the beginning.
I am doing the following:
set<int>::iterator it = myset.begin() + 5;
I am curious why this is not working and what is the correct way to get an iterator to where I want it.
myset.begin() + 5; only works for random access iterators, which the iterators from std::set are not.
For input iterators, there's the function std::advance:
set<int>::iterator it = myset.begin();
std::advance(it, 5); // now it is advanced by five
In C++11, there's also std::next which is similar but doesn't change its argument:
auto it = std::next(myset.begin(), 5);
std::next requires a forward iterator. But since std::set<int>::iterator is a bidirectional iterator, both advance and next will work.
The operator+ doesn’t define for this structure and only It make sense for random access iterators.
First solution:
You can use std::advance, the function uses repeatedly the increase or decrease operator (operator++ or operator--) until n elements have been advanced.
set<int>::iterator it = myset.begin();
std::advance(it, 5);
std::out << *it << std::endl; // == it + 5
Second solution:
Use std::next or std::prev functions,The performance same as the old one because uses repeatedly the increase or decrease operator (operator++ or operator--)until n element have been advanced.
Note: If it is a random access iterator, the function just uses just
once operator+ or operator-.
set<int>::iterator it1 = myset.begin();
std::next(it1, 5); // == it1 + 5
std::out << *it1 << std::endl; // == it1 + 5
set<int>::iterator it2 = myset.end();
std::prev(it2, 5); // == it2 - 5
std::out << *it2 << std::endl; // == it2 - 5
Note: If you want to access, vectors are very efficient accessing its elements (just like arrays) and relatively efficient adding or removing elements from its end.
Get element at index from C++11 std::set
std::set in C++ has no getter by index so you'll have to roll your own by iterating the list yourself and copying into an array then indexing that.
For example:
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
int myarray[uniqueItems.size()]; //create an int array of same size as the
//set<int> to accomodate elements
int i = 0;
for (const int &num : uniqueItems){ //iterate over the set
myarray[i] = num; //assign it to the appropriate array
i++; //element and increment
}
cout << myarray[0] << endl; //get index at zero, prints 10
cout << myarray[1] << endl; //get index at one, prints 20
cout << myarray[2] << endl; //get index at two, prints 30
}
Or a handy dandy function to step through then return the right one:
int getSetAtIndex(set<int> myset, int index){
int i = 0;
for (const int &num : myset){ //iterate over the set
if (i++ == index){
return num;
}
}
string msg = "index " + to_string(index) + \
"is out of range";
cout << msg;
exit(8);
}
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
cout << getSetAtIndex(uniqueItems, 1);
}

check if second to last in an iterator

Is there a clean way to check if I am currently at the second to last element in an iteration in C++? As in:
for (vector::iterator it = v.begin(); it < v.end(); ++it)
{
if (it points to second to last element)
cout << "at second to last";
}
The easiest way would be to compare your iterator against one which does indeed point to the second-to-last. And an easy way to get that is:
vector::iterator secondLast = v.end() - 2;
Assuming of course that v.size() >= 2. But the above doesn't generalize to other container types, for which you could do this:
vector::iterator secondLast = (++v.rbegin()).base();
This should rewind from the last element one step, then convert to a regular (forward) iterator. This will work with other container types like lists.
Or perhaps clearer for the general solution:
vector::iterator secondLast = v.end();
std::advance(secondLast, -2);
Again this requires size of 2 and iterators of random access or bidirectional type.
And finally, a C++11 solution:
auto secondLast = std::prev(v.end(), 2);
Try something like this:
vector::iterator end = v.end(), stl;
bool has_stl = (v.size() >= 2);
if (has_stl) stl = end-2;
for (vector::iterator it = v.begin(); it < end; ++it)
{
if ((has_stl) && (it == stl))
cout << "at second to last";
}
You can do this with some containers:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); it++) {
if (vec.end() - it == 3) {
std::cout << *it << std::endl;
}
}
return 0;
}
A solution below:
auto pos = std::next(std::begin(v), std::distance(std::begin(v), std::end(v))-2);
for (auto it = std::begin(v); it != std::end(v); ++it)
{
if (it == pos)
cout << "at second to last: " << *pos;
}
pos is now an iterator pointing to the second to last position, and the functions std::next and std::distance use the best implementation possible (i.e. constant complexity for random iterators, linear complexity for bidirectional/forward iterators).

Get element from arbitrary index in set

I have a set of type set<int> and I want to get an iterator to someplace that is not the beginning.
I am doing the following:
set<int>::iterator it = myset.begin() + 5;
I am curious why this is not working and what is the correct way to get an iterator to where I want it.
myset.begin() + 5; only works for random access iterators, which the iterators from std::set are not.
For input iterators, there's the function std::advance:
set<int>::iterator it = myset.begin();
std::advance(it, 5); // now it is advanced by five
In C++11, there's also std::next which is similar but doesn't change its argument:
auto it = std::next(myset.begin(), 5);
std::next requires a forward iterator. But since std::set<int>::iterator is a bidirectional iterator, both advance and next will work.
The operator+ doesn’t define for this structure and only It make sense for random access iterators.
First solution:
You can use std::advance, the function uses repeatedly the increase or decrease operator (operator++ or operator--) until n elements have been advanced.
set<int>::iterator it = myset.begin();
std::advance(it, 5);
std::out << *it << std::endl; // == it + 5
Second solution:
Use std::next or std::prev functions,The performance same as the old one because uses repeatedly the increase or decrease operator (operator++ or operator--)until n element have been advanced.
Note: If it is a random access iterator, the function just uses just
once operator+ or operator-.
set<int>::iterator it1 = myset.begin();
std::next(it1, 5); // == it1 + 5
std::out << *it1 << std::endl; // == it1 + 5
set<int>::iterator it2 = myset.end();
std::prev(it2, 5); // == it2 - 5
std::out << *it2 << std::endl; // == it2 - 5
Note: If you want to access, vectors are very efficient accessing its elements (just like arrays) and relatively efficient adding or removing elements from its end.
Get element at index from C++11 std::set
std::set in C++ has no getter by index so you'll have to roll your own by iterating the list yourself and copying into an array then indexing that.
For example:
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
int myarray[uniqueItems.size()]; //create an int array of same size as the
//set<int> to accomodate elements
int i = 0;
for (const int &num : uniqueItems){ //iterate over the set
myarray[i] = num; //assign it to the appropriate array
i++; //element and increment
}
cout << myarray[0] << endl; //get index at zero, prints 10
cout << myarray[1] << endl; //get index at one, prints 20
cout << myarray[2] << endl; //get index at two, prints 30
}
Or a handy dandy function to step through then return the right one:
int getSetAtIndex(set<int> myset, int index){
int i = 0;
for (const int &num : myset){ //iterate over the set
if (i++ == index){
return num;
}
}
string msg = "index " + to_string(index) + \
"is out of range";
cout << msg;
exit(8);
}
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
cout << getSetAtIndex(uniqueItems, 1);
}

iterate an STL container not from the .begin()ing and wrap around

I have an std::vector, let's say of integers for simplicity.
std::vector<int> ivec;
ivec.push_back(1);
ivec.push_back(2);
... //omitting some push back's 3 to 99
ivec.push_back(100);
The standard way to iterate is known
std::map<int>::iterator it;
for( it = ivec.begin(); it != ivec.end(); it++ )
print();
That iteration will print 1,2,3, ... 100.
I want to traverse all vector elements starting from a predefined index and not from it.begin().
I would like to print
3,4,5,6 ... 99, 100, 1, 2
Can you share your thoughts here?
It might ok to do it in two steps
for( it = ivec.begin()+index; it != ivec.end(); it++ ) and then (if index !=0)
for ( it = ivec.begin; it = it = ivec.begin() + (index-1); it++)
You can either:
develop an iterator class that wraps the vector::iterator and expose the behaviour you like (in particular: ++ checks for end() and replace it with begin() and adjust the other "border values")
fill the vector starting from 3 and wrap at 100, so that standard iteration will look as you want.
The choice depends on what else the vector is purposed and what else that iteration is needed.
I'll assume that you already have a starting iterator. How you get this depends on whether you are using an indexable (vector) type or a forward iterator only, or a keyed type. Then you can do a loop something like this:
type::iterator start_iter = /* something from collection, perhaps begin()+index */
type::iterator cur_iter = start_iter;
do
{
//do something with cur_iter
++cur_iter;
if( cur_iter == collection.end() )
cur_iter = collection.begin();
} while( cur_iter != start_iter );
That's the basic loop.
bool wrapped = false;
for (auto it = vec.begin() + index; (it != vec.begin() + index) || !wrapped; ++it)
{
if (it == vec.end())
{
it = vec.begin();
wrapped = true;
}
std::cout << *it;
}
I know this is a pretty old question, but nobody mentioned std::rotate, which I think, in some cases, can be the right tool for the job.
Modified example from http://www.cplusplus.com/reference/algorithm/rotate/:
#include <iostream> // std::cout
#include <algorithm> // std::rotate
#include <vector> // std::vector
int main () {
std::vector<int> myvector;
// set some values:
for (int i = 1; i < 10; ++i) myvector.push_back(i); // 1, 2, 3, ... 9
std::rotate(myvector.begin(), myvector.begin() + 2, myvector.end());
// 3, 4, 5, 6 ... 9, 1, 2
// print out content:
std::cout << "myvector contains:";
for (auto it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
cpp.sh/3rdru
Output:
myvector contains: 3 4 5 6 7 8 9 1 2
Note, since my_vector is modified by the std::rotate function, this is neither very efficient nor useful if you just want to iterate the vector once.
However, while this is probably not the best answer to this SO question, I hope it can still provide some value for people with similar issues.
A solution when using a random-access container is very simple, see the code below.
std::vector<int> v ({1,3,4,5,6,7,8,9,10}); /* c++11 */
...
for (int i = 2; i < (10+2); ++i)
std::cout << v[i % 10] << " ";
Method when using containers only having bidirectional/forward iterators:
std::list<int> l ({1,3,4,5,6,7,8,9,10}); /* c++11 */
Iter start = l.begin ();
std::advance (start, 4);
...
Iter it = start;
do {
std::cerr << *it << std::endl;
} while (
(it = ++it == l.end () ? l.begin () : it) != start
);
There are endless ways to do it, and probably all are (more or less) equivalent, so in the end it depends on personal preference and maybe coding style conventions. I would probably do it like:
std::cout << v[idx] << "\n";
for( auto it = v.begin() + idx + 1; it != v.begin()+idx; ++it )
{
if( it == v.end() ) it = v.begin();
std::cout << *it << "\n";
}