78

Can this Python code be shortened and still be readable using itertools and sets?

result = {}
for widget_type, app in widgets:
    if widget_type not in result:
        result[widget_type] = []
    result[widget_type].append(app)

I can think of this only:

widget_types = zip(*widgets)[0]
dict([k, [v for w, v in widgets if w == k]) for k in set(widget_types)])
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
culebrón
  • 34,265
  • 20
  • 72
  • 110

3 Answers3

130

An alternative to defaultdict is to use the setdefault method of standard dictionaries:

 result = {}
 for widget_type, app in widgets:
     result.setdefault(widget_type, []).append(app)

This relies on the fact that lists are mutable, so what is returned from setdefault is the same list as the one in the dictionary, therefore you can append to it.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 6
    And that's my Python nugget to learn for the day. Thanks, Daniel. :) – Walter Nov 10 '10 at 12:39
  • 1
    My personal opinion: I am opting for `defaultdict` because `setdefault` is, at least in my experience, the method with the most unintelligible name I have ever seen across any language. Also [python docs](https://docs.python.org/3/library/collections.html#defaultdict-examples) suggest to use `defaultdict` _This technique is simpler and faster than an equivalent technique using `dict.setdefault()`_ – Antonio Aug 17 '22 at 12:06
94

You can use a defaultdict(list).

from collections import defaultdict

result = defaultdict(list)
for widget_type, app in widgets:
    result[widget_type].append(app)
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 8
    +1 As stated in https://docs.python.org/3.7/library/collections.html#defaultdict-objects : *This technique is simpler and faster than an equivalent technique using `dict.setdefault()`* – Marco Nov 10 '19 at 11:57
  • 1
    Related: [How to convert a `default_dict` to `dict`](https://stackoverflow.com/a/20428703/2436175). – Antonio Aug 17 '22 at 12:20
6

may be a bit slow but works

result = {}
for widget_type, app in widgets:
    result[widget_type] = result.get(widget_type, []) + [app]
user1139002
  • 81
  • 1
  • 2