Incrementing counter at insert type with a set 
Author Message
 Incrementing counter at insert type with a set

Hey all-

I'm trying to simulate a SQL "group by" using the STL. I've been able to do
it with a map, where I overload the assigment operator of the object and
insert into the map doing something along the lines of mymap[key] =
myobject. Inside the assignment operator, I call ++counter.

Okay, all's well and good, but I don't need a key per se, I just have a list
of objects that I want to see how many times duplicates get "added" (to save
space, because the objects could be so big, and because it's a group by,
it's a set and not a multiset). The immediate difference is having to call
insert(), and when I stepped through it, my assigment operator never got
called.

The set contains a structure of type foo, and I have overloaded the <
operator for proper sorting (thanks to the folks earlier to pointed out
where I went wrong writing that!). Inside the < operator, the first thing I
do to see is if the elements are equal, at which time I call ++counter. I
tested it, and it seems to work. I don't think it's necessary, but I did a
check that this != &foo (see code below).

So my question is: Is this a valid way of doing it? Like I said, it does
seem to be working in my limited testing, but before I got really involved,
I want to make sure I'm doing the "right" thing. If the STL provides a
better way, I'm all for it.

Thanks for any info,

Ron

#pragma warning(disable:4786)

#include <set>

#include <string>

using namespace std;

struct Foo

{

Foo() : counter(1)

{}

string strData;

int x;

double d;

mutable int counter;

bool operator < ( const Foo& foo ) const

{

if ( (x == foo.x && d == foo.d && strData == foo.strData)

&&

(this != &foo)

)

++counter;

if (x < foo.x) return true;

if (foo.x < x) return false;

if (d < foo.d) return true;

if (foo.d < d) return false;

return strData < foo.strData;

Quote:
}

Foo& operator=(const Foo& foo)

{

printf("op=\n"); // never got called

Quote:
}
};

int main(int argc, _char** argv)

{

set<Foo> foos;

Foo f1;

f1.strData = "hi there";

f1.x = 325;

f1.d = 9962.113;

foos.insert(f1);

Foo f2;

f2.strData = "bubba baby";

f2.x = 901;

f2.d = 1963.21;

foos.insert(f2);

set<Foo>::iterator it;

for ( it = foos.begin(); it != foos.end(); ++it )

{

printf("%s: %d\n", it->strData.c_str(), it->counter);

Quote:
}

Foo f3;

f3.strData = "bubba baby";

f3.x = 901;

f3.d = 1963.21;

foos.insert(f3);

Foo f4;

f4.strData = "bubba baby";

f4.x = 901;

f4.d = 1963.21;

foos.insert(f4);

for ( it = foos.begin(); it != foos.end(); ++it )

{

printf("%s: %d\n", it->strData.c_str(), it->counter);

Quote:
}

return 0;
Quote:
}



Fri, 31 Dec 2004 12:23:02 GMT  
 Incrementing counter at insert type with a set
set::insert returns a pair (iterator, bool). The iterator points to the
element equivalent to the one you are inserting, and bool determines
whether the element was actually inserted (true) or an existing element
has been found (false). So you can do something like this:

typedef set<Foo> FooSet;
std::pair<FooSet::iterator, bool> myPair = foos.insert(foo);
if (myPair.second)
{
    // actual insertion - reference count is 1
    myPair.first->counter = 1;

Quote:
}

else
{
    // the element already exists - increment reference count
    ++myPair.first->counter;

Quote:
}

I wouldn't rely on operator<. It is implementation-dependent, you may
get false positives, and it looks like a hack, hurting maintainability.
Also, to establish equivalence, the set has to compare the elements
twice, since (a is equivalent to b) is determined as (!(a < b) && !(b <
a)). Your code would increment reference count on both a and b.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Quote:
> Hey all-

> I'm trying to simulate a SQL "group by" using the STL. I've been able
to do
> it with a map, where I overload the assigment operator of the object
and
> insert into the map doing something along the lines of mymap[key] =
> myobject. Inside the assignment operator, I call ++counter.

> Okay, all's well and good, but I don't need a key per se, I just have
a list
> of objects that I want to see how many times duplicates get "added"
(to save
> space, because the objects could be so big, and because it's a group
by,
> it's a set and not a multiset). The immediate difference is having to
call
> insert(), and when I stepped through it, my assigment operator never
got
> called.

> The set contains a structure of type foo, and I have overloaded the <
> operator for proper sorting (thanks to the folks earlier to pointed
out
> where I went wrong writing that!). Inside the < operator, the first
thing I
> do to see is if the elements are equal, at which time I call
++counter. I
> tested it, and it seems to work. I don't think it's necessary, but I
did a
> check that this != &foo (see code below).

> So my question is: Is this a valid way of doing it? Like I said, it
does
> seem to be working in my limited testing, but before I got really
involved,
> I want to make sure I'm doing the "right" thing. If the STL provides a
> better way, I'm all for it.

> Thanks for any info,

> Ron

> #pragma warning(disable:4786)

> #include <set>

> #include <string>

> using namespace std;

> struct Foo

> {

> Foo() : counter(1)

> {}

> string strData;

> int x;

> double d;

> mutable int counter;

> bool operator < ( const Foo& foo ) const

> {

> if ( (x == foo.x && d == foo.d && strData == foo.strData)

> &&

> (this != &foo)

> )

> ++counter;

> if (x < foo.x) return true;

> if (foo.x < x) return false;

> if (d < foo.d) return true;

> if (foo.d < d) return false;

> return strData < foo.strData;

> }

> Foo& operator=(const Foo& foo)

> {

> printf("op=\n"); // never got called

> }

> };

> int main(int argc, _char** argv)

> {

> set<Foo> foos;

> Foo f1;

> f1.strData = "hi there";

> f1.x = 325;

> f1.d = 9962.113;

> foos.insert(f1);

> Foo f2;

> f2.strData = "bubba baby";

> f2.x = 901;

> f2.d = 1963.21;

> foos.insert(f2);

> set<Foo>::iterator it;

> for ( it = foos.begin(); it != foos.end(); ++it )

> {

> printf("%s: %d\n", it->strData.c_str(), it->counter);

> }

> Foo f3;

> f3.strData = "bubba baby";

> f3.x = 901;

> f3.d = 1963.21;

> foos.insert(f3);

> Foo f4;

> f4.strData = "bubba baby";

> f4.x = 901;

> f4.d = 1963.21;

> foos.insert(f4);

> for ( it = foos.begin(); it != foos.end(); ++it )

> {

> printf("%s: %d\n", it->strData.c_str(), it->counter);

> }

> return 0;

> }



Sat, 01 Jan 2005 02:40:03 GMT  
 
 [ 2 post ] 

 Relevant Pages 

1. performance issue in using set::find and set::insert with comparision function specified

2. Incrementing enumerated types

3. Impossible to add field of counter type

4. Setting increment amount on up/down control?

5. pre-increment v.s. post-increment

6. pre increment and post increment

7. C line counter (bean counter)

8. How to Insert or select text data type?

9. Insert HTML source into Oralce LONG Type Column..

10. How to programatically set Caps Lock and Insert

11. Inserting Excel and Word type libraries

12. set.insert

 

 
Powered by phpBB® Forum Software