简体   繁体   中英

sort a nested list of dicts by key in python

Below is an example nested list of dictionaries. I want to order the lists by the number of points that Charlie has.

l = [[{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 10}],
     [{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 30}],
     [{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 20}]]

The output should look like this.

l = [[{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 10}],
     [{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 20}],
     [{'Name': 'Alice',   'Age': 40, 'Point': 80},
      {'Name': 'Bob',     'Age': 20             },
      {'Name': 'Charlie', 'Age': 30, 'Point': 30}]]

I think I should be able to use sorted() with the right arguments, but I'm not sure what the syntax would be.

sorted(l, key=lambda x: x[ ????? ])

Charlie is always the third item in the sublists.

Use a lambda to search for Charlie's point in the nested lists:

l.sort(key=lambda lst: next(d.get('Point', 0) for d in lst if d.get('Name')=='Charlie'))
print(l)

If you want a new list:

out = sorted(l, key=lambda lst: next(d.get('Point', 0) for d in lst if d.get('Name')=='Charlie'))

Output:

[[{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 10}],
 [{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 20}],
 [{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 30}]]

If Charlie is always third, you could use this:

sorted(l, key=lambda x: x[2]['Point'])

Otherwise, you'd want to use a helper function:

def get_charlie_points(lst):
    for item in lst:
        if item['Name'] == 'Charlie':
            return item['Point']
    return 0  # Replace this with the number you want if there is no Charlie, or raise an exception

sorted(l, key=get_charlie_points)

Very similar to @enke's answer, but using next to provide the default 0 , rather than the get method.

s = sorted(l, key=lambda lst: next((d['Point'] for d in lst if d['Name'] == 'Charlie'), 0))

If Charlie is always third, keep it simple, use:

out = sorted(l, key=lambda x:x[2].get('Point', float('inf')))

NB. I used a default value of infinite if Charlie has no points, to push it to the end.

Output:

[[{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 10}],
 [{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 20}],
 [{'Name': 'Alice', 'Age': 40, 'Point': 80},
  {'Name': 'Bob', 'Age': 20},
  {'Name': 'Charlie', 'Age': 30, 'Point': 30}]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM