Q: STL vector

D

David Jones

Hi

I have a list of values stored in a vector e.g.

std::vector<int> x;

x[0] = 1;
x[1] = 4;
x[2] = 2;
x[3] = 4;
x[4] = 6;
x[5] = 1;
x[6] = 4;

Can anybody suggest an efficient way to iterate through the vector so that
the vector only contains unique values e.g. only one instance of 4 occurs in
the vector. That is, the new vector, once processed, would be:

{1,4,2,6}

Thanks in advance

David
 
P

Paul Thompson

David Jones said:
Hi

I have a list of values stored in a vector e.g.

std::vector<int> x;

x[0] = 1;
x[1] = 4;
x[2] = 2;
x[3] = 4;
x[4] = 6;
x[5] = 1;
x[6] = 4;

Can anybody suggest an efficient way to iterate through the vector so that
the vector only contains unique values e.g. only one instance of 4 occurs in
the vector. That is, the new vector, once processed, would be:

{1,4,2,6}

Look up std::sort and std::unique in an STL reference. Example:

std::sort(x.begin(), x.end());
std::unique(x.begin(), x.end());

You'll need to include <algorithm> first.

HTH,

Paul
 
D

David Jones

Many thanks for your prompt reply Paul. Very useful!

To simplify the problem I've specified a vector of integers. However, as
with most things in life, the true problem I'm trying to solve is a little
bit more complex. The vector I have is not a vector of integers but a vector
of objects which have a member identifying a name i.e. each object has a
char member. The elements of the vector have this member set as "A", "B"
etc. I want to remove elements from the vector which have identical "names"
i.e. only one vector will, for example, have name "C".

I guess that this is the same type of problem, hence my initial post, but a
little more complex.

Any advice will be most appreciated.

David
 
J

John Harrison

Paul Thompson said:
David Jones said:
Hi

I have a list of values stored in a vector e.g.

std::vector<int> x;

x[0] = 1;
x[1] = 4;
x[2] = 2;
x[3] = 4;
x[4] = 6;
x[5] = 1;
x[6] = 4;

Can anybody suggest an efficient way to iterate through the vector so that
the vector only contains unique values e.g. only one instance of 4
occurs
in
the vector. That is, the new vector, once processed, would be:

{1,4,2,6}

Look up std::sort and std::unique in an STL reference. Example:

std::sort(x.begin(), x.end());
std::unique(x.begin(), x.end());

You'll need to include <algorithm> first.

HTH,

Paul

Except of course std::unique, like any other STL algorithm, will not
actually erase the items from the vector. You need to do

ox.erase(std::unique(ox.begin(), ox.end()), ox.end());

for that.

john
 
K

Karl Heinz Buchegger

David said:
Many thanks for your prompt reply Paul. Very useful!

To simplify the problem I've specified a vector of integers. However, as
with most things in life, the true problem I'm trying to solve is a little
bit more complex. The vector I have is not a vector of integers but a vector
of objects which have a member identifying a name i.e. each object has a
char member. The elements of the vector have this member set as "A", "B"
etc. I want to remove elements from the vector which have identical "names"
i.e. only one vector will, for example, have name "C".

No problem.
All you need is a comparison function (or a functor)
which can be feed to sort() and unique(). This comparison
function determines what it means for 2 objects to be less.

Or you could add an operator< to your class which does the same.
 
P

Paul Thompson

David Jones said:
Many thanks for your prompt reply Paul. Very useful!


I can't actually see my reply on the news server, but I was wrong on two
counts. You need to pass the result of std::unique to erase thus:

std::sort(x.begin(), x.end());
x.erase(std::unique(x.begin(), x.end()), x.end());

That's one.

Two: Your example had the result not in ascending order; whereas if you
follow my advice, it will be.

Other than that, yes, std::unique is very useful.

To simplify the problem I've specified a vector of integers. However, as
with most things in life, the true problem I'm trying to solve is a little
bit more complex. The vector I have is not a vector of integers but a vector
of objects which have a member identifying a name i.e. each object has a
char member. The elements of the vector have this member set as "A", "B"
etc. I want to remove elements from the vector which have identical "names"
i.e. only one vector will, for example, have name "C".

I guess that this is the same type of problem, hence my initial post, but a
little more complex.

Any advice will be most appreciated.

I think the other replies handle the rest quite well.

Paul
 
P

Paul Thompson

John Harrison said:
Paul Thompson said:
David Jones said:
Hi

I have a list of values stored in a vector e.g.

std::vector<int> x;

x[0] = 1;
x[1] = 4;
x[2] = 2;
x[3] = 4;
x[4] = 6;
x[5] = 1;
x[6] = 4;

Can anybody suggest an efficient way to iterate through the vector so that
the vector only contains unique values e.g. only one instance of 4
occurs
in
the vector. That is, the new vector, once processed, would be:

{1,4,2,6}

Look up std::sort and std::unique in an STL reference. Example:

std::sort(x.begin(), x.end());
std::unique(x.begin(), x.end());

You'll need to include <algorithm> first.

HTH,

Paul

Except of course std::unique, like any other STL algorithm, will not
actually erase the items from the vector. You need to do

ox.erase(std::unique(ox.begin(), ox.end()), ox.end());


Absolutely right - I was just about to pop out for lunch, but thought I'd
answer David's query. As soon as I left the office, I could have kicked
myself!

Paul
 
P

Peter Gregory

David said:
Many thanks for your prompt reply Paul. Very useful!

To simplify the problem I've specified a vector of integers. However, as
with most things in life, the true problem I'm trying to solve is a little
bit more complex. The vector I have is not a vector of integers but a
vector of objects which have a member identifying a name i.e. each object
has a char member. The elements of the vector have this member set as "A",
"B" etc. I want to remove elements from the vector which have identical
"names" i.e. only one vector will, for example, have name "C".

I guess that this is the same type of problem, hence my initial post, but
a little more complex.

Any advice will be most appreciated.

David

Overload the < operator so sort can work, and the == operator to define
equality and I think you're away.

Pete
 
J

John Dibling

Firstly, this solution is not immediately implementable in iterator form.

What? Please explain this statement.

</dib>

John Dibling
email: dib@substitute_my_full_last_name_here.com
Witty banter omitted for your protection
 
A

Andrey Tarasevich

John said:
...

What? Please explain this statement.
...

The straightforward approach to implementing the
'std::sort'+'std::unique' variant in form of an iterator would be
creating and iterating a copy of the original vector, which is not
exactly the same as iterating the original vector itself. Of course,
this problem can be solved by some additional efforts. That's why I said
that it is "not _immediately_ implementable".
 
A

Agent Mulder

I have a list of values stored in a vector e.g.

std::vector<int> x;

x[0] = 1;
x[1] = 4;
x[2] = 2;
x[3] = 4;
x[4] = 6;
x[5] = 1;
x[6] = 4;

Can anybody suggest an efficient way to iterate through the vector so that
the vector only contains unique values e.g. only one instance of 4 occurs in
the vector. That is, the new vector, once processed, would be:

{1,4,2,6}

DJ> However, as with most things in life, the true problem I'm trying
DJ> to solve is a little bit more complex. The vector I have is not a
DJ> vector of integers but a vector of objects which have a member
DJ> identifying a name i.e. each object has a char member. The elements
DJ> of the vector have this member set as "A", "B" etc. I want to
DJ> remove elements from the vector which have identical "names"
DJ> i.e. only one vector will, for example, have name "C".


The way you fill your vector is wrong. The vector x is
empty, so the elements you're trying to assign to don't
exist.


#include <iostream.h>
#include <list.h>
#include <set.h>
#include <vector.h>
#include <algorithm.h>
class MyObject
{
public:char name;
public:MyObject(const char&a='A'){name=a;}
};
bool operator<(const MyObject&a,const MyObject&b){return a.name<b.name;}
void show(const MyObject&a){cout<<'\t'<<a.name;}
void debug(const vector<MyObject>&a)
{
cout<<"\nVector contains "<<a.size()<<" elements: ";
for_each(a.begin(),a.end(),show);
}
int main(int argv,char**argc)
{
vector<MyObject>x;
x.push_back(MyObject('A'));
x.push_back(MyObject('D'));
x.push_back(MyObject('B'));
x.push_back(MyObject('D'));
x.push_back(MyObject('F'));
x.push_back(MyObject('A'));
x.push_back(MyObject('D'));
debug(x);
set<MyObject>s(x.begin(),x.end());
x.resize(s.size());
copy(s.begin(),s.end(),x.begin());
debug(x);
}

-X
 
J

John Dibling

The straightforward approach to implementing the
'std::sort'+'std::unique' variant in form of an iterator would be
creating and iterating a copy of the original vector, which is not
exactly the same as iterating the original vector itself. Of course,
this problem can be solved by some additional efforts. That's why I said
that it is "not _immediately_ implementable".

Well, if you are willing to sort the original vector (which I believe
the OP is *not*, even tho this wasn't stated), then there is no need
to copy elements to a temporary vector. In fact, doing so is the
Wrong Thing.

Aside from that, in industrial code I think you would agree that
effort is required to accomplish anything in a robust manner.

</dib>

John Dibling
email: dib@substitute_my_full_last_name_here.com
Witty banter omitted for your protection
 
C

Chris \( Val \)

| On Fri, 18 Jul 2003 21:47:53 +1000, "Chris \( Val \)"
|
| >
| >Anyway, here is a sample for you to scrutinise :), and hopefully
| >the OP can make some use of it:
| >
| [snip]
| > while( Idx != V.end() )
| > {
| > std::vector<T>::iterator Pos( std::find( V.begin(), Idx, *Idx ) );
| > ( Pos == Idx ) ? ++Idx : Idx = V.erase( Idx );
| > }
| > }
| [snip]
|
| The code snippet above is the kay to your algorithm. This relies on
| the iterative technique I mentioned in my original reply to the OP. I
| think the method is fine; in fact, I generally use the same technique
| unless I am compelled not to for whatever reason. I cannot criticize
| the general method.
|
| On the other hand, if you would like me to constructively criticize
| the *style* (which I know is always dangerous), I would offer the
| following.
|
| <OPINION>

[snip]

Thanks for your opinion, and another point of view.

My sample wasn't meant to mimic the generic algorithms
used, however, I will study your example.

Cheers.
Chris Val
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,126
Messages
2,570,752
Members
47,313
Latest member
SamualGriz

Latest Threads

Top