Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use itertools.groupby when the key value is in the elements of the iterable?

To illustrate, I start with a list of 2-tuples:

import itertools
import operator

raw = [(1, "one"),
       (2, "two"),
       (1, "one"),
       (3, "three"),
       (2, "two")]

for key, grp in itertools.groupby(raw, key=lambda item: item[0]):
    print key, list(grp).pop()[1]

yields:

1 one
2 two
1 one
3 three
2 two

In an attempt to investigate why:

for key, grp in itertools.groupby(raw, key=lambda item: item[0]):
    print key, list(grp)

# ---- OUTPUT ----
1 [(1, 'one')]
2 [(2, 'two')]
1 [(1, 'one')]
3 [(3, 'three')]
2 [(2, 'two')]

Even this will give me the same output:

for key, grp in itertools.groupby(raw, key=operator.itemgetter(0)):
    print key, list(grp)

I want to get something like:

1 one, one
2 two, two
3 three

I am thinking this is because the key is within the tuple inside the list, when in fact the tuple gets moved around as one. Is there a way to get to my desired output? Maybe groupby() isn't suited for this task?

like image 303
Kit Avatar asked Aug 09 '10 13:08

Kit


People also ask

How do you use Groupby Itertools?

The groupby() function takes two arguments: (1) the data to group and (2) the function to group it with. Here, lambda x: x[0] tells groupby() to use the first item in each tuple as the grouping key. In the above for statement, groupby returns three (key, group iterator) pairs - once for each unique key.

What does the chain () Itertool do?

chain() function It groups all the iterables together and produces a single iterable as output. Its output cannot be used directly and thus explicitly converted into iterables. This function come under the category iterators terminating iterators.

Is Itertools faster than for loops?

That being said, the iterators from itertools are often significantly faster than regular iteration from a standard Python for loop.

What does Itertools Zip_longest return?

zip_longest() This iterator falls under the category of Terminating Iterators. It prints the values of iterables alternatively in sequence.


1 Answers

From the docs:

The operation of groupby() is similar to the uniq filter in Unix. It generates a break or new group every time the value of the key function changes (which is why it is usually necessary to have sorted the data using the same key function). That behavior differs from SQL’s GROUP BY which aggregates common elements regardless of their input order.

Since you are sorting the tuples lexicographically anyway, you can just call sorted:

for key, grp in itertools.groupby( sorted( raw ), key = operator.itemgetter( 0 ) ):
    print( key, list( map( operator.itemgetter( 1 ), list( grp ) ) ) )
like image 131
Katriel Avatar answered Oct 19 '22 01:10

Katriel