3

I need to get only unique values from the field "city" in my dictionary. I need to do it using list/dict comprehension.

people = [ dict ( city = "Liverpool" , name = "Adam" , age = 24 ),
{ "city" : "New York" , "name" : "Dario" , "age" : 12 },
{ "city" : "New York" , "name" : "Mario" , "age" : 45 },
{ "city" : "Chicago" , "name" : "Paolo" , "age" : 27 },
{ "city" : "Brighton" , "name" : "Sven" , "age" : 19 },
{ "city" : "Berlin" , "name" : "Frank" , "age" : 52 },
{ "city" : "Rome" , "name" : "Aleksander" , "age" : 33 }
{ "city" : "Rome" , "name" : "Adam," , "age" : 24 }]

I've done it with loop this way:

unique_cities = []
for x in range(len(people)):
    y = people[x]
    cities = y.get('city')
    unique_cities.append(cities)
unique_cities = list(dict.fromkeys(unique_cities))
print(unique_cities)

But I haven't dealt with list/dict comprehension before. I can only print all values like this:

for x in range(len(people)):
    y = people[x]
    dict_comp = {k:v for (k, v) in y.items()}
    print(dict_comp)
glhr
  • 4,439
  • 1
  • 15
  • 26
krmnow
  • 31
  • 1

3 Answers3

4

List comprehension, and pass it to a set.

set(person['city'] for person in people)

note: actually, this is a generator expression, not a list comprehension, but in this case they are equivalent for most purposes

blue_note
  • 27,712
  • 9
  • 72
  • 90
2

Entries in a set are unique by definition, so a set comprehension is exactly what you need here:

{d["city"] for d in people}

Output:

{'Berlin', 'Rome', 'Brighton', 'Liverpool', 'Chicago', 'New York'}
glhr
  • 4,439
  • 1
  • 15
  • 26
0

First, note that your list contains two syntaxes for dictionary definition: dict + keywords and key: value inside accolades. That's not a problem, but that's weird.

Second, in Python you usually don't need the index of the loop:

for x in range(len(people)):
    y = people[x]
    ...

Is the same as:

for y in people:
    ...

If you need the index, you have the enumerate keyword:

for x, y in enumerate(people):
    ...

Third:

    dict_comp = {k:v for (k, v) in y.items()}

makes a (shallow) copy of y and assigns it to dict_comp. That's not required in your case:

for y in people:
    print(y)

Fourth, dict.fromkeys is the poor man's set. Both solutions are roughly equivalent, but set looses the order of insertion (tested in 3.6) whereas dict.fromkeys keeps the order insertion of a key (>= 3.6):

>>> set(person['city'] for person in people)
{'Rome', 'Chicago', 'New York', 'Brighton', 'Liverpool', 'Berlin'}
>>> dict.fromkeys(person['city'] for person in people)
{'Liverpool': None, 'New York': None, 'Chicago': None, 'Brighton': None, 'Berlin': None, 'Rome': None}

If you want the order of the first apparition of a key, you can also write:

>>> seen = set()
>>> [person['city'] for person in people if not (person['city'] in seen or seen.add(person['city']))]
['Liverpool', 'New York', 'Chicago', 'Brighton', 'Berlin', 'Rome']

Every time a new city is met, the list comprehension adds it to the output and to the seen set (beware: side effect inside the list comprehension):

>>> seen
{'Berlin', 'Liverpool', 'Rome', 'New York', 'Brighton', 'Chicago'}
jferard
  • 7,835
  • 2
  • 22
  • 35