Why the std::map storing fewer elements than expected? - c++

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.

Related

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);
}

Detect equal elements in a std::list

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());
}

Deleting an object from an vector [duplicate]

I have a std::vector<int>, and I want to delete the n'th element. How do I do that?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
To delete a single element, you could do:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));
Or, to delete more than one element at once:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
The erase method on std::vector is overloaded, so it's probably clearer to call
vec.erase(vec.begin() + index);
when you only want to erase a single element.
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
The erase method will be used in two ways:
Erasing single element:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Erasing range of elements:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Erase an element with index :
vec.erase(vec.begin() + index);
Erase an element with value:
vec.erase(find(vec.begin(),vec.end(),value));
Actually, the erase function works for two profiles:
Removing a single element
iterator erase (iterator position);
Removing a range of elements
iterator erase (iterator first, iterator last);
Since std::vec.begin() marks the start of container and if we want to delete the ith element in our vector, we can use:
vec.erase(vec.begin() + index);
If you look closely, vec.begin() is just a pointer to the starting position of our vector and adding the value of i to it increments the pointer to i position, so instead we can access the pointer to the ith element by:
&vec[i]
So we can write:
vec.erase(&vec[i]); // To delete the ith element
If you have an unordered vector you can take advantage of the fact that it's unordered and use something I saw from Dan Higgins at CPPCON
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
Since the list order doesn't matter, just take the last element in the list and copy it over the top of the item you want to remove, then pop and delete the last item.
It may seem obvious to some people, but to elaborate on the above answers:
If you are doing removal of std::vector elements using erase in a loop over the whole vector, you should process your vector in reverse order, that is to say using
for (int i = v.size() - 1; i >= 0; i--)
instead of (the classical)
for (int i = 0; i < v.size(); i++)
The reason is that indices are affected by erase so if you remove the 4-th element, then the former 5-th element is now the new 4-th element, and it won't be processed by your loop if you're doing i++.
Below is a simple example illustrating this where I want to remove all the odds element of an int vector;
#include <iostream>
#include <vector>
using namespace std;
void printVector(const vector<int> &v)
{
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
int main()
{
vector<int> v1, v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i);
}
// print v1
cout << "v1: " << endl;
printVector(v1);
cout << endl;
// print v2
cout << "v2: " << endl;
printVector(v2);
// Erase all odd elements
cout << "--- Erase odd elements ---" << endl;
// loop with decreasing indices
cout << "Process v2 with decreasing indices: " << endl;
for (int i = v2.size() - 1; i >= 0; i--)
{
if (v2[i] % 2 != 0)
{
cout << "# ";
v2.erase(v2.begin() + i);
}
else
{
cout << v2[i] << " ";
}
}
cout << endl;
cout << endl;
// loop with increasing indices
cout << "Process v1 with increasing indices: " << endl;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] % 2 != 0)
{
cout << "# ";
v1.erase(v1.begin() + i);
}
else
{
cout << v1[i] << " ";
}
}
return 0;
}
Output:
v1:
0 1 2 3 4 5 6 7 8 9
v2:
0 1 2 3 4 5 6 7 8 9
--- Erase odd elements ---
Process v2 with decreasing indices:
# 8 # 6 # 4 # 2 # 0
Process v1 with increasing indices:
0 # # # # #
Note that on the second version with increasing indices, even numbers are not displayed as they are skipped because of i++
Note also that processing the vector in reverse order, you CAN'T use unsigned types for indices (for (uint8_t i = v.size() -1; ... won't work). This because when i equals 0, i-- will overflow and be equal to 255 for uint8_t for example (so the loop won't stop as i will still be >= 0, and probably out of bounds of the vector).
If you work with large vectors (size > 100,000) and want to delete lots of elements, I would recommend to do something like this:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
The code takes every number in vec that can't be divided by 3 and copies it to vec2. Afterwards it copies vec2 in vec. It is pretty fast. To process 20,000,000 elements this algorithm only takes 0.8 sec!
I did the same thing with the erase-method, and it takes lots and lots of time:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
I suggest to read this since I believe that is what are you looking for.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
If you use for example
vec.erase(vec.begin() + 1, vec.begin() + 3);
you will erase n -th element of vector but when you erase second element, all other elements of vector will be shifted and vector sized will be -1. This can be problem if you loop through vector since vector size() is decreasing. If you have problem like this provided link suggested to use existing algorithm in standard C++ library. and "remove" or "remove_if".
Hope that this helped
To delete an element use the following way:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
For a more broad overview you can visit: http://www.cplusplus.com/reference/vector/vector/erase/
if you need to erase an element inside of a for-loop, do the following:
for(int i = 0; i < vec.size(); i++){
if(condition)
vec.erase(vec.begin() + i);
}
You need to use the Standard Template Library's std::vector::erase function.
Example: Deleting an element from a vector (using index)
// Deleting the eleventh element from vector vec
vec.erase( vec.begin() + 10 );
Explanation of the above code
std::vector<T,Allocator>::erase Usage:
iterator erase (iterator position); // until C++11
iterator erase( const_iterator pos ); // since C++11 and until C++20
constexpr iterator erase( const_iterator pos ); // since C++20
Here there is a single parameter, position which is an iterator pointing to a single element to be removed from the vector.
Member types iterator and const_iterator are random access iterator types that point to elements.
How it works
erase function does the following:
It removes from the vector either a single element (position) or a range of elements ([first, last)).
It reduces the container size by the number of elements removed, which are destroyed.
Note: The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for pos.
Return value and Complexity
The return value is an iterator pointing to the new location of the element that followed the last element that was erased by the function call. This is the container end of the operation that erased the last element in the sequence.
Member type iterator is a random access iterator type that points to elements.
Here, the time complexity is linear on the number of elements erased (destructions) plus the number of elements after the last element is deleted (moving).
The previous answers assume that you always have a signed index. Sadly, std::vector uses size_type for indexing, and difference_type for iterator arithmetic, so they don't work together if you have "-Wconversion" and friends enabled. This is another way to answer the question, while being able to handle both signed and unsigned:
To remove:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
To take:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
here is one more way to do this if you want to delete a element by finding this with its value in vector,you just need to do this on vector.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
it will remove your value from here.
thanks
the fastest way (for programming contests by time complexity() = constant)
can erase 100M item in 1 second;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
and most readable way :
vec.erase(vec.begin() + pos);

Split vector to unique and duplicates c++

My goal is to split a vector into two parts: with unique values and with duplicates.
For example I have sorted vector myVec=(1,1,3,4,4,7,7,8,9,9) which should be split into myVecDuplicates=(1,7,4,9) and myVecUnique=(1,4,7,9,3,8). So myVecDuplicates contains all values that have duplicates while myVecUnique contains all values but in a single embodiment.
The order does not matter. My idea was to use unique as it splits a vector into two parts. But I have a problem running my code.
vector<int> myVec(8)={1,1,3,4,4,7,8,9};
vector<int>::iterator firstDuplicate=unique(myVec.begin(),myVec.end());
vector<int> myVecDuplicate=myVec(firstDuplicate,myVec.end());\\here error accures that says ' no match for call to '(std::vector<int>) (std::vector<int>::iterator&, std::vector<int>::iterator)'
vector<int> myVecUnique=myVec(myVec.begin()+firstDuplicate-1,myVec.end());
After running this code I get an error that says (2nd line) 'no match for call to '(std::vector) (std::vector::iterator&, std::vector::iterator)'
Please help me to understand the source of error or maybe suggest some more elegant and fast way to solve my problem (without hash tables)!
Ahh..Too many edits in your question for anyone's liking. Just keep it simple by using map.
In C++, map comes really handy in storing the unique + sorted + respective_count values.
map<int, int> m;
for(auto &t : myVec){
m[t]++;
}
vector<int> myVecDuplicate, myVecUnique;
for(map<int, int>::iterator it = m.begin(); it != m.end(); it++){
if(it->second > 1) myVecDuplicate.push_back(it->first);
myVecUnique.push_back(it->first);
}
Edit:
maybe suggest some more elegant and fast way to solve my problem (without hash tables)!
Sort the vector
Traverse through the sorted vector,
and do
if (current_value == previous_value){
if(previous_value != previous_previous_value)
myVecDuplicate.push_back(current_value);
}
else{
myVecUnique.push_back(current_value);
}
To start, initialize previous_value = current_value - 1
and previous_previous_value as current_value - 2.
While this may be frowned upon (for not using standard algorithms and such), I would write some simple solution like this:
vector<int> myVec = {1,1,3,4,4,7,8,9};
unordered_set<int> duplicates;
unordered_set<int> unique;
for(int & v : myVec)
{
if(unique.count(v) > 0)
duplicates.insert(v);
else
unique.insert(v);
}
O(n) complexity solution:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> myVec = {1,1,3,4,4,7,7,8,9,9};
std::vector<int> myVecDuplicatec;
std::vector<int> myVecUnique;
for(int &x : myVec)
{
if(myVecUnique.size() == 0 || myVecUnique.back() != x)
myVecUnique.push_back(x);
else
myVecDuplicatec.push_back(x);
}
std::cout << "V = ";
for(int &x : myVec)
{
std::cout << x << ",";
}
std::cout << std::endl << "U = ";
for(int &x : myVecUnique)
{
std::cout << x << ",";
}
std::cout << std::endl << "D = ";
for(int &x : myVecDuplicatec)
{
std::cout << x << ",";
}
}
cpp.sh/4i45x
std::vector has a constructor that accepts 2 iterators for range [first,second[ You cannot call constructor for existing object - it is already created, so your code
myVec(firstDuplicate,myVec.end());
actually tries to use myVec as a functor, but std::vector does not have operator() hence the error.
you have 2 ways, pass 2 iterators to constructor directly:
vector<int> myVecDuplicate(firstDuplicate,myVec.end());
or use copy initialization with temporary vector:
vector<int> myVecDuplicate = vector<int>(firstDuplicate,myVec.end());
Same for the second vector:
vector<int> myVecUnique(myVec.begin(),firstDuplicate);
as pointed by Logman std::unique does not seem to guarantee value of duplicates, so working solution can use std::set instead (and you would not have to presort source vector):
std::set<int> iset;
vector<int> myVecUnique, myVecDuplicate;
for( auto val : myVec )
( iset.insert( val ).second ? myVecUnique : myVecDuplicate ).push_back( val );

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);
}