Python: Lists to Dictionary - python

I'm writing this question despite the many answers on stackoverflow as the solutions did not work for my problem.
I have 2 Lists, List1 and List2. When I dict(zip(List1,List2)) the order of the elements inside the dictionary are disturbed.
print s_key
print value
sorted_dict = {k: v for k,v in zip(s_key,value)}
another_test = dict(zip(s_key,value))
print sorted_dict
print another_test
print zip(s_key,value))
Terminal :
[2, 1, 3]
[31, 12, 5]
{1: 12, 2: 31, 3: 5}
{1: 12, 2: 31, 3: 5}
[(2, 31), (1, 12), (3, 5)]
I was under the impression that the [(2, 31), (1, 12), (3, 5)] would be converted to a dict
Any help to understand where or what I'm doing wrong would help! Thanks!

a=[2, 1, 3]
b=[31, 12, 5]
from collections import OrderedDict
print(OrderedDict(zip(a,b)))

You cannot sort a dictionary, in your case if you wanted to display sorted key/values of your dictionary you can convert it to a list of tuples as you have and sort it by whichever element you want. In the code below it creates a list of tuples and sorts by the first element in the tuples:
l1,l2=[2, 1, 3],[31, 12, 5]
print ([(one,two) for (one,two) in
sorted(zip(l1,l2),key=lambda pair: pair[0])])
prints:
[(1, 12), (2, 31), (3, 5)]
shoutout to Sorting list based on values from another list? for the help
Either that or create a list of the dictionaries keys and sort the list then loop through the list and call each key
Or use ordered dict as others have pointed out

Related

Different ways to access tuples created with zip built-in function

I want to sort a tuple of integers(in decreasing order) and I then want to save a tuple with the order of indices after sorting in a set. The following piece of code does the job:
my_set = set()
l = (1, 3, 6, 10, 15, 21)
my_set.add(list(zip(*sorted(enumerate(l), key=lambda x: x[1], reverse=True)))[0])
If I evaluate my_set I now have {(5, 4, 3, 2, 1, 0)}
I was trying to do the same with the following code(i for indices, v for values):
my_set.add(i for i, v in zip(*sorted(enumerate(l), key=lambda x: x[1], reverse=True)))
It doesn't work in the same way. The set becomes { <generator object <genexpr> at 0x7f82e49ce360>}
Why is it that if I feed the zip result into a list I can access the tuples inside but I can't use the other syntax?
Is there an alternative way of obtaining some tuple created by zip without having to feed into a list and then indexing into it?
Look at the output that zip returns.
>>> list(zip(*sorted(enumerate(l), key=lambda x: x[1], reverse=True)))
[(5, 4, 3, 2, 1, 0), (21, 15, 10, 6, 3, 1)]
It's always going to be a list of 2 tuples - one tuple being the argsorted indices, and the other being the actual sorted items.
First up, you don't realise this because you're hashing a generator inside a set... but when you decide to exhaust the generator, be prepared for a
ValueError: too many values to unpack (expected 2)
In summary, you're iterating over zip incorrectly. You don't even need to iterate over zip, if it's just the first tuple you're interested in.
What you should instead do, is use next;
>>> my_set.add(next(zip(*sorted(enumerate(l), key=lambda x: x[1], reverse=True))))
>>> my_set
{(5, 4, 3, 2, 1, 0)}
Which gets you just the first tuple.

Comparing a list of tuples

I want to compare a list of tuples, if the first elements are the same then compare the second elements and return the highest.
lis = [(1,10, "n"), (1,15,"n1"), (2,20,"n"),(2,35,"n1"),(3,123,"n"),(3,12,"n1")]
return:
lis = [(1,15,"n1"), (2,35,"n1"), (3,123,"n")]
I'm not sure how to go about this, any help would be appreciated.
I'd use itertools.groupby to first group all items with the same first element together, then max to find the items with the max second element.
Unlike some other answers you may have varying number of elements from different "groups".
from itertools import groupby
from operator import itemgetter
lis = [(1,10, "n"), (1,15,"n1"), (2,20,"n"), (2,35,"n1"), (3,123,"n"),(3,12,"n1")]
lis.sort(key=itemgetter(0)) # groupby requires the iterable to be sorted,
# so making sure it is
grouped_by = groupby(lis, key=itemgetter(0))
output = [max(li, key=itemgetter(1)) for group, li in grouped_by]
print(output)
# [(1, 15, 'n1'), (2, 35, 'n1'), (3, 123, 'n')]
Tuple comparisons do that already, comparing first elements then second and continuing until a tie-breaker is found.
All you need to do is zip the list in such a way to create the correct comparisons:
zip(lis[::2], lis[1::2])
# This produces:
# (1, 10, 'n') (1, 15, 'n1')
# (2, 20, 'n') (2, 35, 'n1')
# (3, 123, 'n') (3, 12, 'n1')
Creates the pairs you need, you can then compare them inside a list-comprehension to get the wanted results:
r = [i if i > j else j for i,j in zip(lis[::2], lis[1::2])]
print(r)
# [(1, 15, 'n1'), (2, 35, 'n1'), (3, 123, 'n')]
The solution using range() and max() functions:
lis = [(1,10, "n"), (1,15,"n1"), (2,20,"n"),(2,35,"n1"),(3,123,"n"),(3,12,"n1")]
result = [max(lis[i:i+2]) for i in range(0, len(lis), 2)]
print(result)
The output:
[(1, 15, 'n1'), (2, 35, 'n1'), (3, 123, 'n')]

Convert a dictionary into a list of tuples

Given a dictionary like this:
dic = {(7, 3): 18.51, (1, 3): 18.751, (5, 6): 34.917, (9, 8): 18.9738}
I want to convert it to a list of tuples like this:
my_list = [(7, 3, 18.51), (1, 3, 18.751), (5, 6, 34.917), (9, 8, 18.9738)]
I could have used a loop but I wonder if there is a neat way to do so instead of loops.
Simply use list(..) on some generator:
my_list = list(key+(val,) for key,val in dic.items())
This works since:
list(..) takes as input an iterable and converts it to a list; and
key+(val,) for key,val dic.items() is a generator that takes a pair of key-values of dic and transforms it into a tuple appending the val to the key.
Since we use a generator for a list, we can simplify this with list comprehension:
my_list = [key+(val,) for key,val in dic.items()]
Finally mind that the order in which the tuples occur is not fixed this is because the order how a dict stores elements is not fixed as well.

Find duplicates in a list of lists with tuples

I am trying to find duplicates within tuples that are nested within a list. This whole construction is a list too. If there are other better ways to organize this to let my problem to be solved - I'd be glad to know, because this is something I build on the way.
pairsList = [
[1, (11, 12), (13, 14)], #list1
[2, (21, 22), (23, 24)], #list2
[3, (31, 32), (13, 14)], #list3
[4, (43, 44), (21, 22)], #list4
]
The first element in each list uniquely identifies each list.
From this object pairsList, I want to find out which lists have identical tuples. So I want to report that list1 has the same tuple as list3 (because both have (13,14). Likewise, list2 and list4 have the same tuple (both have (21,22)) and need to be reported. The position of tuples within the list doesn't matter (list2 and list4 both have (13,14) even though the position in the list the tuple has is different).
The output result could be anything iterable later on such as (1,3),(2,4) or [1,3],[2,4]. It is the pairs I am interested in.
I am aware of sets and have used them to delete duplicates within the lists in other situations, but cannot understand how to solve this problem. I can check like this if one list contains any element from the other list:
list1 = [1, (11, 12), (13, 14)]
list2 = [3, (31, 32), (13, 14)]
print not set(list1).isdisjoint(list2)
>>>True
So, the code below lets me know what lists have same tuple(s) as the first one. But what is the correct way to perform this on all the lists?
counter = 0
for pair in pairsList:
list0 = pairsList[0]
iterList = pairsList[counter]
if not set(list0).isdisjoint(iterList):
print iterList[0] #print list ID
counter += 1
The first element in each list uniquely identifies each list.
Great, then let's convert it to a dict first:
d = {x[0]: x[1:] for x in pairsList}
# d:
{1: [(11, 12), (13, 14)],
2: [(21, 22), (23, 24)],
3: [(31, 32), (13, 14)],
4: [(43, 44), (21, 22)]}
Let's index the whole data structure:
index = {}
for k, vv in d.iteritems():
for v in vv:
index.setdefault(v, []).append(k)
Now index is:
{(11, 12): [1],
(13, 14): [1, 3],
(21, 22): [2, 4],
(23, 24): [2],
(31, 32): [3],
(43, 44): [4]}
The output result could be anything iterable later on such as (1,3),(2,4) or [1,3],[2,4]. It is the pairs I am interested in.
pairs = [v for v in index.itervalues() if len(v) == 2]
returns [[1,3],[2,4]].

Converting nested lists to dictionary

Hi please I try to make a dictionary out of the nested lists below and I get a TypeError. Please help me fix it to get the desired output as shown below. Thanks
n1 = [[1,2],[3,4]]
n2 = [[(5,7),(10,22)],[(6,4),(8,11)]]
output = {1:(5,7), 2:(10,22), 3:(6,4), 4:(8,11)}
D1 = {}
for key, value in zip(n1,n2):
D1[key] = value
print D1
TypeError: unhashable type: 'list'
Your approach didn't work, because when you zip n1 and n2, the result will be like this
for key, value in zip(n1,n2):
print key, value
# [1, 2] [(5, 7), (10, 22)]
# [3, 4] [(6, 4), (8, 11)]
So, key is a list. But, it is not hashable. So it cannot be used as an actual key to a dictionary.
You can chain the nested lists to get them flattened and then you can zip them together with izip
from itertools import chain, izip
print dict(izip(chain.from_iterable(n1), chain.from_iterable(n2)))
# {1: (5, 7), 2: (10, 22), 3: (6, 4), 4: (8, 11)}
The beauty of this method is that, it will be very memory efficient, as it doesn't create any intermediate lists. So, this can be used even when the actual lists are very large.
Perhaps not the most pythonic way, but it's short:
In [8]: dict(zip(sum(n1, []), sum(n2, [])))
Out[8]: {1: (5, 7), 2: (10, 22), 3: (6, 4), 4: (8, 11)}
The sum() trick, is used for flattening the list.
Try this:
from itertools import chain
n1 = [[1,2],[3,4]]
n2 = [[(5,7),(10,22)],[(6,4),(8,11)]]
print dict(zip(chain(*n1), chain(*n2))

Categories