Reputation: 7268
I have a default dict d
in python which contains two list in it as below:
{
'data1': [0.8409093126477928, 0.9609093126477928, 0.642217399079215, 0.577003839123445, 0.7024399719949195, 1.0739533732043967],
'data2': [0.9662666242560285, 0.9235637581239243, 0.8947656867577896, 0.9266919525550584, 1.0220039913024457]
}
In future there can be many list in in default dict like data1
, data2
, data3
, data4
etc. I need to compare the index values of default dict with each other. So for above default dict I need to check weather data1[0]->0.8409093126477928
is smaller than data2[0]->0.9662666242560285
or not and same goes for other index, and store the result of wining list index in separate list like below:
result = ['data1', 'data2', 'data1', 'data1', 'data1']
If length of any list is greater than other list, we simply need to check if the last index value is smaller than 1 or not. Like data1[5]
cannot be compared with data2[5]
because there is no value of data2[5]
thus we will simply check if data1[5]
is less than 1 or not. If its less than 1 then we will consider it and add it to result
otherwise ignore it and will not save it in result
.
To resolve this I thought, of extracting the list from default dict to separate list and then using a for loop to compare index values, but when I did print(d[0])
to print the 0th
index list, it printed out []
. Why is it printing null. How can I compare the index values as above. Please help. Thanks
Upvotes: 3
Views: 836
Reputation: 5471
Edit: as suggested by @ggorlen replaced the custom iterator with zip_longest
I would do it using custom_iterator like this,
item.index(min(item))
then get the key corresponding to the min value keys[item.index(min(item))]
from itertools import zip_longest
keys = list(d.keys())
lengths = list(map(len,d.values()))
result = [keys[item.index(min(item))]
for i, item in enumerate(zip_longest(*d.values(), fillvalue=1))
if lengths[item.index(min(item))]>i]
result
if you want to give default key instead of skip-ing when minimum value found is not less than one
result = [keys[item.index(min(item))] if lengths[item.index(min(item))]>i else "NA"
for i, item in enumerate(zip_longest(*d.values(), fillvalue=1))]
Upvotes: 1
Reputation: 334
d = {
'd0': [0.1, 1.1, 0.3],
'd1': [0.4, 0.5, 1.4, 0.3, 1.6],
'd2': [],
}
import itertools
import collections
# sort by length of lists, shortest first and longest last
d = sorted(d.items(), key=lambda k:len(k[1]))
# loop through all combinations possible
for (key1, list1), (key2, list2) in itertools.combinations(d, 2):
result = []
for v1, v2 in itertools.zip_longest(list1, list2): # shorter list is padded with None
# no need to check if v2 is None because of sorting
if v1 is None:
result.append(key2 if v2 < 1 else None)
else:
result.append(key1 if v1 < v2 else key2)
# DO stuff with result, keys, list, etc...
print(f'{key1} vs {key2} = {result}')
Output
d2 vs d0 = ['d0', None, 'd0']
d2 vs d1 = ['d1', 'd1', None, 'd1', None]
d0 vs d1 = ['d0', 'd1', 'd0', 'd1', None]
I sorted them based on the list lengths. This ensures that list1
will always be shorter or of the same length as list2
.
For different lengths, the remaining indices will be a mixture of None
and key2
.
However, when the elements are equal, key2
is added to the result. This might not be the desired behavior.
Upvotes: 1
Reputation: 57155
We can use zip_longest
from itertools and a variety of loops to achieve the result:
from itertools import zip_longest
result = []
pairs = [[[z, y] for z in x] for y, x in data.items()]
for x in zip_longest(*pairs):
x = [y for y in x if y]
if len(x) > 1:
result.append(min(x, key=lambda x: x[0])[1])
elif x[0][0] < 1:
result.append(x[0][1])
print(result) # => ['data1', 'data2', 'data1', 'data1', 'data1']
First we create pairs of every item in each dict value and its key. This makes it easier to get result keys later. We zip_longest
and iterate over the lists, filtering out None
s. If we have more than one element to compare, we take the min and append it to the result, else we check the lone element and keep it if its value is less than 1.
A more verifiable example is
data = {
'foo': [1, 0, 1, 0],
'bar': [1, 1, 1, 1, 0],
'baz': [1, 1, 0, 0, 1, 1, 0],
'quux': [0],
}
which produces
['quux', 'foo', 'baz', 'foo', 'bar', 'baz']
Element-wise, "quux"
wins round 0, "foo"
wins round 1, "baz"
2, "foo"
round 3 thanks to key order (tied with "baz"
), "bar"
for round 4. For round 5, "baz"
is the last one standing but isn't below 1, so nothing is taken. For round 6, "baz"
is still the last one standing but since 0 < 1, it's taken.
Upvotes: 1