Python: How to query a list of objects?

Question:

Let’s say I have this list of objects:

listt = [{
      "CustomerId": "1",
      "Date": "2017-02-02",
      "Content": "AAAAAAAA",
      "Type": 2
    },
    {
      "CustomerId": "2",
      "Date": "2017-02-03",
      "Content": "BBBBBBBB",
      "Type": 1
    },
    {
      "CustomerId": "3",
      "Date": "2017-02-01",
      "Content": "CCCCCCCCC",
      "Type": 1
    },
    {
      "CustomerId": "4",
      "Date": "2017-02-12",
      "Content": "DDDDDDDDDD",
      "Type": 2
    }, ]

What’s the cleanest way of finding answers to these?

  1. Minimum Date where Type = 1.

=> 2017-02-1

  1. Select Content where Type = 2 and Date = (Minimum Date among all objects with Type = 2)

=> AAAAAAAA

I’m reading about leveraging lambda and filters but I haven’t been able to make any progress. What can I try next?

Asked By: 90abyss

||

Answers:

These are basic Python data structures. Rather than map and filter I would suggest using comprehensions. E.g.:

>>> listt = [{
...       "CustomerId": "1",
...       "Date": "2017-02-02",
...       "Content": "AAAAAAAA",
...       "Type": 2
...     },
...     {
...       "CustomerId": "2",
...       "Date": "2017-02-03",
...       "Content": "BBBBBBBB",
...       "Type": 1
...     },
...     {
...       "CustomerId": "3",
...       "Date": "2017-02-01",
...       "Content": "CCCCCCCCC",
...       "Type": 1
...     },
...     {
...       "CustomerId": "4",
...       "Date": "2017-02-12",
...       "Content": "DDDDDDDDDD",
...       "Type": 2
...     }, ]
>>> min(d['Date'] for d in listt if d['Type'] == 1)
'2017-02-01'
>>>

Or, for you second query:

>>> min_date = min(d['Date'] for d in listt if d['Type'] == 2)
>>> [d['Content'] for d in listt if d['Date'] == min_date]
['AAAAAAAA']
>>>

Trying to stick to comprehension constructs keeps things more readable, IMO, rather than using lambda, although, that also has its place and is rather a matter of style. However, list-comprehensions are faster in general than equivalent map with lambda. However, map can be faster with built-in functions.

Answered By: juanpa.arrivillaga

For finding the minimum date with type=1, you may firstly filter the list on type=1 and then pass the filtered list to min function (with key as lambda x: x['Date'] to find element with minimum ‘Date’) as:

#                        performs `min` operation on `'Date'` v
>>> min([d for d in listt if d['Type'] ==1], key=lambda x: x['Date'])
{'CustomerId': '3', 'Type': 1, 'Content': 'CCCCCCCCC', 'Date': '2017-02-01'}

This is a dict object having the minimum Date in the list. Let’s say it is stored as variable my_dict. In order to find the date, do:

my_dict['Date']

For finding the content associated to it, do:

my_dict['Content']

Note: For finding the content of Type=2, replace d['Type'] ==1 with d['Type'] ==2 in the min statement.

Answered By: Moinuddin Quadri

Here’s a version with comprehensions. For the first question:

minval = min(elem['CustomerId'] for elem in listt if elem['Type']==1)
print(minval)

For the second version, you probably don’t want to search for the minimum first and then compare every element to the minimum as this would require to traverse the list twice. Instead, it is better to search for the minimum and keep track of its index. This can be easily done in a comprehension using the enumerate function:

minval, index = min((elem['CustomerId'], _) 
                    for _, elem in enumerate(listt) if elem['Type']==2)
print(minval, listt[index])
Answered By: Andi Kleve
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.