remove duplicates entry in vectors - c++

I am trying to add objects using class(Sample),sort my vector and after that remove duplicates entries in my vector.
my codes (this is just part of my codes in my program)
vector<Sample> sampleVector;
sort(sampleVector.begin(), sampleVector.end());
sampleVector.erase(std::unique(sampleVector.begin(),sampleVector.end(),sampleVector.end()));
but however it when I tried to run my program it shows this error.
Type 'std::__1::__wrap_iter<Sample *>' does not provide a call operator
and I realized that most likely the error is caused by this line
sampleVector.erase(std::unique(sampleVector.begin(),sampleVector.end(),sampleVector.end()));
What should I do so that I can make it work to remove duplicate entries in my vector?
thanks in advance
Another thing I have tried but it's not working.
bool myfunction (Sample *i,Sample *j) {
return (i==j);
}
std::vector<Sample>::iterator it;
vector<Sample> sampleVector;
it = std::unique(sampleVector.begin(), sampleVector.end(),myfunction);
for (it=sampleVector.begin(); it!=sampleVector.end(); ++it) {
std::cout << *it << " "; <-- error must change it to &*it
}

Misplaced parenthesis. Correction:
sampleVector.erase( std::unique(sampleVector.begin(),sampleVector.end()),
sampleVector.end() );
I don't blame you for getting caught out. C++ compiler errors are heinous.

I think you can try this code below
bool myfunction (int i, int j) {
return (i==j);
}
std::unique (myvector.begin(), myvector.end(), myfunction);
std::cout << "myvector contains:";
for (it=myvector.begin(); it!=myvector.end(); ++it){
std::cout << ' ' << *it;
}
std::cout << '\n';
Hope it will help!

Another possibility worth considering is that you could put the sorted elements into an std::set. That will retain the sorted ordering and ensure item uniqueness.

Related

Duplicating std::list with std::copy and removal with std::list::erase

In the bellow example code after assigning example list with numbers I'm trying to duplicate container with std::copy but problem is at runtime it says "cannot dereference end list iterator".
my question is how do I duplicate the list so that duplicated range is inserted to the end of the list?
to the end because I later need to be able to remove duplicated range, that is why I save the beginning of the new range to iterator.
#include <iostream>
#include <list>
#include <algorithm>
void print(std::list<int>& ref)
{
for (auto& num : ref)
{
std::cout << num << std::endl;
}
}
int main()
{
std::list<int> mylist{ 1, 2, 3, 4 };
std::list<int>::iterator iter = mylist.end();
std::cout << "INITIAL LIST NUMBERS" << std::endl;
print(mylist);
// duplicate list, will cause runtime error
iter = std::copy(mylist.begin(), mylist.end(), --mylist.end());
std::cout << "COPIED LIST IS NOW CONTAINS DUPLICATE NUMBERS" << std::endl;
print(mylist);
// remove previsous duplication
mylist.erase(iter, mylist.end());
std::cout << "AFTER REMOVAL OF COPIED LIST SHOULD BE SAME AS INITIAL LIST" << std::endl;
print(mylist);
std::cin.get();
return 0;
}
You can use std::copy_n. This circumvents the issue with std::copy, which would execute an infinite loop of insertions when fed with a std::back_inserter(mylist) and an always valid mylist.end() iterator.
const std::size_t n = mylist.size();
std::copy_n(mylist.cbegin(), n, std::back_inserter(mylist));
De-duplication then works with
mylist.erase(std::next(mylist.begin(), n), mylist.end());
if (!mylist.empty()) --iter;
std::copy_n(mylist.begin(), mylist.size(), std::back_inserter(mylist));
if (!mylist.empty()) ++iter;
Unfortunately we can't use end iterator in copy(), since it might lead to an infinite loop, as new elements are added between the end and the current iterator all the time.

Print vector elements with iterator

I'm trying to print elements of a vector of list pair in a hash-table program in C++.
If I use the C++11 auto it's working but if i use a iterator
for (vector<int>::iterator i = arr_Hash[i].begin(); i != arr_Hash[i].end(); ++i)
//for (auto index = arr_Hash[i].begin(); index != arr_Hash[i].end(); index++)
{
cout << i->second;
cout << " ";
}
Error list: https://i.imgur.com/rDejBGG.png
How can I use the iterator here?
vector<int>::iterator i = arr_Hash[i].begin()
You're reusing the variable i here. Call it something else.
std::cout << i->second;
i is a std::vector<int>::iterator. Dereferencing it gives you an int&, which has no second member. You probably just want std::cout << *i;
The iterator for arr_Hash[i] needs to be on the same type as the vector.
Namely, if the type of arr_Hash[i] is vector<pair<int,int>> then it's iterator needs to be vector<pair<int,int>>::iterator.
Howerver, you should Prefer a range-for-statement to a for-statement when there is a choice.
for (auto& e : arr_Hash[i])
cout << i->second << " ";

Check if the element is the first or the last one in an std::vector

I have the following for each C++ code:
for (auto item : myVector)
{
std::cout << item;
if (item == orderBy.IsLast()) // <--- Check if this is the last element
std::cout << "(Is last element) " << std::endl;
else if (item == orderBy.IsFirst()) // <-- Check if this is the first element
std::cout << "(Is first element)" << std::endl;
}
Of course IfLast() and IfFirst() do not exist on std::vector. Is there a native std:: way to check for first and last element ?
You shouldn't use the range-based for in this case, as this kind of for "hides" the iterator, and you'd need an additional counter to keep track of the position in vector. You can simply do
for(auto it = myVector.begin(); it != myVector.end(); ++it)
{
if(it == myVector.begin()) // first element
{
// do something
}
else if(std::next(it) == myVector.end()) // last element
{
// do something else
}
}
Note that simply comparing my.Vector.back() with your element from a range-based for is OK only if you're sure that you don't have duplicates in the vector. But if e.g. the value of the last element appears multiple times in the vector, you're going to find only its first position. So that's why there's really no good way of using a range-based for without an additional index that keeps track of where exactly in the vector you are.
EDIT See also #thelink2012's answer for how to "trick" your range-based for so you can get the position of the element implicitly.
Use the std::vector::front and std::vector::back to get a reference to the data in the first and last positions.
Reference is a keyword here because you could efficiently check the address of your iterating item and the address of the respective front/back references. In your example you take the item by value not reference so this prehaps wouldn't work, take in consideration this example that'd work with this method:
for(auto& item : myVector) // take item by reference
{
std::cout << item;
if (&item == &myVector.back())
std::cout << "(last element) " << std::endl;
else if (&item == &myVector.front())
std::cout << "(first element)" << std::endl;
}
If the object overloads the address of operator & (though it's considered a bad practice) you might want to use std::addressof instead.
This method won't work however for the std::vector<bool> specialization since it optimizes the vector to store booleans efficiently with bits, and since we cannot have references to bits, all references taken out this data structure is a proxy object not exactly tied to the address of the internal data.
Use std::vector::front() for the first element.
Use std::vector::back() for the last element.
Before you call those functions, make sure that the vector is not empty.
if (!orderBy.empty() && item == orderBy.back()) <--- Check if this is the last element
else if (!orderBy.empty() && item == orderBy.front()) <-- Check if this is the first element
For value based comparison, you may use myVector.front()/myVector[0] as the first and myVector.back()/myVector[myVector.size()-1] as the last element.
Suggestion
Capture the reference by default to avoid unwanted copies. e.g.
for(const auto& I : myVector)
You could search for it again, but that would be rather inefficient. If you need information on the position of the current item, you probably want to use an iterator or an index:
for (std::size_t i=0; i<myVector.size(); ++i)
{
auto& item = myVector[i];
std::cout << item;
if (i == (myVector.size() - 1))
std::cout << "(Is last element) " << std::endl;
else if (i == 0)
std::cout << "(Is first element)" << std::endl;
}
If you have special cases for the boundaries you should use the ol' iterator version, but separating the first and last cases away from the loop.
If the cases share the code after that if you should encapsulate it on a function.
I can't write code from my phone :c
This works for me
vector<int> vi {1,2,3,4};
cout << "vi = {";
for (const auto &e : vi) {
cout << e;
if (&e != &vi.back())
cout << ',';
}
cout << '}' << endl;

STL vector usage problem -- Function returning non-zero Iterator

I was trying to use the vector STL, where iam facing a weird response from the following sample program :
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int>::iterator fun();
vector<int> myvector;
bool IsOdd (int i) {
return ((i%2)==1);
}
int main()
{
vector<int>::iterator it;
it = fun();
if (it == myvector.end() )
cout << "Reached end, Global" << endl;
else
cout << "Not end" << endl;
}
vector<int>::iterator fun() {
vector<int>::iterator it;
myvector.push_back(10);
myvector.push_back(26);
myvector.push_back(40);
myvector.push_back(56);
it = find_if (myvector.begin(), myvector.end(), IsOdd);
cout << "The first odd value is " << *it << endl;
if (it == myvector.end() )
cout << "Reached end, inside the function" << endl;
else
cout << "Not end" << endl;
return it;
}
Iam getting "Reached End" inside the function fun(), whereas, in the main program, it is showing up as "Not End".
Not sure, what might be the reason. Also, found that, the Address of myvector.end() is showing up as Zero in the main program [ after the fun() call ], where-as, showing a non-zero value inside the function fun().
The function is using the local myvector, main is using the global one.
Your modified code produces:
Reached end, inside the function
Reached end, Global
as expected.
Edit: Well, not as expected - as others have pointed out:
it = find_if (myvector.begin(), myvector.end(), IsOdd);
cout << "The first odd value is " << *it << endl;
will cause undefined behaviour with your dataset, because you don't have any odd values. You want:
it = find_if (myvector.begin(), myvector.end(), IsOdd);
if ( it != myvector.end() ) {
cout << "The first odd value is " << *it << endl;
}
There are two different myvectors, one is global, another is in fun. Therefore, you're comparing an iterator to the global vector with an iterator to a local vector which moreover doesn't exist anymore.
You have two instances of vector with name myvector. One global and one local to function fun. Inside fun this local vector hides the global vector. Since you are operating on two totally different vector objects you are seeing these results.
You dereferenced *it without checking if it was before the end. None of your vector values are odd, so it will be end and you will cause undefined behaviour by dereferencing it.

std::swap returns 0xBAADF00D

I'm trying to swap two std::list< dontcare* >::iterators under Visual 2005.
Iter it1 = ... ,it2 = ...; // it1 and it2 are ok, not end() or such
if(...){
std::swap(it1,it2);
}
The swap works, but when I leave the if() scope, it1 points to 0xbaadfood. It2 is ok though.I tried several variations, including swap_iter and a hand-made swap.
Any help appreciated :)
EDIT
Ok, so shame time.
The swapped it1 was a local variable in the if's scope.
F**king cut'n pasting. Sorry for wasting your time :/
This following program
#include <iostream>
#include <vector>
#include <algorithm>
int main(){
std::vector<int> v;
for(std::vector<int>::size_type idx=0; idx<10; ++idx)
v.push_back(static_cast<int>(idx));
std::vector<int>::iterator it1 = v.begin();
std::vector<int>::iterator it2 = v.begin() + v.size()/2;
std::cout << static_cast<void*>(&*it1) << ':' << *it1
<< ' ' << static_cast<void*>(&*it2) << ':' << *it2 << '\n';
std::swap(it1,it2);
std::cout << static_cast<void*>(&*it1) << ':' << *it1
<< ' ' << static_cast<void*>(&*it2) << ':' << *it2 << '\n';
return 0;
}
compiles, runs, and, as expected, prints
00032A28:0 00032A3C:5
00032A3C:5 00032A28:0
for me.
If it does something else for you, either your compiler or your standard library is broken.
If it does the same for you, then the error is somewhere in the difference between your code and my code. Where, we can't know, because we don't know your code.
Are you omitting code inside your if? Most likely something else within your if check, but after the swap is actually invalidating the iterator (perhaps an erase).
A WAG but perhaps swap is constructing new objects and copying them (and the copy is not valid because it uses the default constructor)?