I need to loop over a dataset which is sorted, grouping all the results by that sorted attribute into chunks which all have the same value for that attribute. Then I run some operations on that chunk of results.
Sorry that’s a bit confusing, examples are probably a better way of describing what I’m doing:
I’ve got a dataset that’s structured like this except the “data” strings are actually objects and contain plenty of other data.
[ [1, "data1"], [1, "data2"], [2, "moredata"], [2, "stuff"],
[2, "things"], [2, "foo"], [3, "bar"], [4, "baz"] ]
What I want to happen is for that data to get grouped into 4 different function calls:
process_data(1, ["data1", "data2"])
process_data(2, ["moredata", "stuff", "things", "foo"])
process_data(3, ["bar"])
process_data(4, ["baz"])
What I end up with is a construct that looks something like this:
last_id = None
grouped_data = []
for row in dataset:
id = row[0]
data = row[1]
if last_id != id:
# we're starting a new group, process the last group
processs_data(last_id, grouped_data)
grouped_data = []
last_id = id
grouped_data.append(data)
if grouped_data:
# we're done the loop and we still have a last group of data to process
# if there was no data in the dataset, grouped_data will still be empty
# so we won't accidentally process any empty data.
process_data(last_id, grouped_data)
It works, but it seems clumsy. Especially the need to track everything with the last_id variable as well as the second call to process_data after the loop. I’d just like to know if anyone can offer any suggestions for a more elegant/clever solution.
My language of choice is Python, but a general solution is fine.
itertools.groupby is just what you want:
Pass groupby a sorted list, and a key function on what to group by within each item in the list. You get back a generator of
(key,itemgenerator)pairs, as shown being passed to my made-up process_data method.[Added 8 Aug 2023]
I have more details in a pair of blog posts on groupby, starting with this one.