Carlos Eduardo Corpus
Carlos Eduardo Corpus

Reputation: 349

Creating a dictionary from two lists but keeping the minimum values

I'm working with a dictionary, and I'm having a problem, so let's say I have two lists that I need to create a dict, I know, I can use zip to do this, but the thing is, the list I'm using for keys ( list1 ) have similar tuples. This is just an example, the lists can have more elements, but the len in both lists are always the same.

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = dict(zip(list1, list2))

print(mydict)

Output:

{(3, 2): 68, (2, 4): 29, (4, 3): 59, (4, 2): 3}

I know that the keys are unique, and if two keys are the same, the associated value will be the last one to appear, but what I need it's that if two keys are the same, then, the associated value needs to be the minimum. For example, in list1 I have two tuples repeated (2,4) with associated values of 34 and 29, so when the dictionary is created I need to keep the 29, and the other duplicated tuple is (4,3) with values of 29 and 59, and if the dictionary is created I want the value to be 29, not 59. my desired output:

{(3, 2): 68, (2, 4): 29, (4, 3): 29, (4, 2): 3}

There is some way I can achieve this? Any help will be appreciated, thank you!

Upvotes: 3

Views: 216

Answers (5)

Andrew Holmgren
Andrew Holmgren

Reputation: 1275

Rather than trying to do a complicated, convoluted one liner or comprehension, a simple for loop will perform fine and maintain readability. My suggestion would be something like this

def merge_lists(list1, list2):
    mydict = {}
    for k, v in zip(list1,list2):
        if (k not in mydict) or (mydict[k] > v):
            mydict[k] = v
    return mydict

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = merge_lists(list1, list2)

print(mydict)

# mydict = {(3, 2): 68, (2, 4): 29, (4, 3): 29, (4, 2): 3}

If you want to play with it more, some further ideas would be to sort list 2 and move the indices of list1 in tandem. Then, with that structure, if you get a repeated element in list1 you know it must it must have come second. You wouldn't really get any perfomance boost or other benefit, but it is an alternative.

Upvotes: 2

Simon Charette
Simon Charette

Reputation: 5116

from operator import itergetter
from itertools import groupby

pairs = sorted(zip(list1, list2))
minima = {
    key: min(value for _, value in group)
    for key, group in groupby(sorted(pairs), itemgetter(0))
}

Upvotes: 1

Karl Knechtel
Karl Knechtel

Reputation: 61617

Starting with

keys = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]
values = [68, 34, 29, 29, 3, 59]

Make key-value pairs that are sorted by value, descending, then build the dict from that:

>>> dict(sorted(zip(keys, values), key=lambda x: -x[1]))
{(3, 2): 68, (4, 3): 29, (2, 4): 29, (4, 2): 3}

It's the same idea as your existing dict(zip()) combination but re-ordering the values before building the dictionary, such that entries with lower values appear later - therefore, the minimum value for the key is last to appear.

Upvotes: 4

Tadhg McDonald-Jensen
Tadhg McDonald-Jensen

Reputation: 21453

one way is to sort the entries so that minimum value is last in the list:

def get_value(pair): return pair[1]

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = dict(sorted(zip(list1, list2), key=get_value, reverse=True))

Upvotes: 3

Jan Stránský
Jan Stránský

Reputation: 1691

One solution is to fill mydict step-by-step:

list1 = [(3, 2), (2, 4), (2, 4), (4, 3), (4, 2), (4, 3)]

list2 = [68, 34, 29, 29, 3, 59]

mydict = {}
for k,v in zip(list1,list2):
    if k in mydict:
        mydict[k] = min(mydict[k],v)
    else:
        mydict[k] = v

print(mydict)

There must be IMO a one-liner solution if desired :-)

Upvotes: 2

Related Questions