This is a variation of itertools.groupby. The itertools.groupby iterator assumes that the input is not sorted but will fit in memory. This iterator has the same API, but assumes the opposite. Example usage:: >>> for (key, subiter) in groupbysorted( ... ((1, 1)
(iterable, keyfunc=None)
| 63 | |
| 64 | |
| 65 | def groupbysorted(iterable, keyfunc=None): |
| 66 | |
| 67 | """This is a variation of itertools.groupby. |
| 68 | |
| 69 | The itertools.groupby iterator assumes that the input is not sorted |
| 70 | but will fit in memory. This iterator has the same API, but assumes |
| 71 | the opposite. |
| 72 | |
| 73 | Example usage:: |
| 74 | |
| 75 | >>> for (key, subiter) in groupbysorted( |
| 76 | ... ((1, 1), (1, 2), (2, 1), (2, 3), (2, 9)), |
| 77 | ... keyfunc=lambda row: row[0]): |
| 78 | ... print "New key:", key |
| 79 | ... for x in subiter: |
| 80 | ... print "Row:", x |
| 81 | ... |
| 82 | New key: 1 |
| 83 | Row: (1, 1) |
| 84 | Row: (1, 2) |
| 85 | New key: 2 |
| 86 | Row: (2, 1) |
| 87 | Row: (2, 3) |
| 88 | Row: (2, 9) |
| 89 | |
| 90 | This requires the peekable class. See my comment here_. |
| 91 | |
| 92 | Note, you must completely iterate over each subiter or groupbysorted will |
| 93 | get confused. |
| 94 | |
| 95 | .. _here: |
| 96 | http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/304373 |
| 97 | |
| 98 | """ |
| 99 | |
| 100 | iterable = peekable(iterable) |
| 101 | |
| 102 | if not keyfunc: |
| 103 | def keyfunc(x): |
| 104 | return x |
| 105 | |
| 106 | def peekkey(): |
| 107 | return keyfunc(iterable.peek()) |
| 108 | |
| 109 | def subiter(): |
| 110 | while True: |
| 111 | if peekkey() != currkey: |
| 112 | break |
| 113 | yield iterable.next() |
| 114 | |
| 115 | while True: |
| 116 | currkey = peekkey() |
| 117 | yield (currkey, subiter()) |