Create dictionary from list elements in Python - python

I have a list similar to the following:
my_list =
[(1, 'item_19'),
(2, 'item_20'),
(3, 'item_21'),
(4, 'item_22'),
(5, 'item_23'),
(6, 'item_24'),
(7, 'item_25'),
(8, 'item_26'),
(9, 'item_27'),
(10, 'item_28'),
(11, 'item_29'),
(12, 'item_30'),
(13, 'item_31'),
(14, 'item_32'),
(15, 'item_33'),
(16, 'item_34'),
(17, 'item_35')]
I would like to make a dictionary of each element of the list, i.e. 1:'item_19',2:'item_20'
I currently do this:
list_1 = [l[0] for l in my_list]
list_2 = [l[1] for l in my_list]
and then zip the two lists
my_dict = dict(zip(list_1,list_2))
However there are more than a million element in my_list, so is this the best way to do this, or is there a quicker/more optimal way to do it(Memory wise).
To put this in context, I want a lookup table to check if elements in my_dict already exist in a different dictionary my_dict_old

The builtin dict function takes a list of tuples, which is exactly what you are providing:
>>> list_foo = [(1, 'item_1'), (2, 'item_2')]
>>> dict(list_foo)
{1: 'item_1', 2: 'item_2'}
If all you need to do is check for an item's existence, consider using set, as i in my_set is much faster than i in my_dict.values(), see the Python documentation on performance for more info. On my machine, for example, a lookup in a haystack of 10k entries is .443s with dict.values(), vs <.000s for set. If you need to associate values with the entries, then use a dictionary, otherwise use a set. For a more in-depth examination of lists vs. dictionaries (and also sets for the most part), refer to this answer.

dict accepts list of tuples, so you can just use your original list:
my_dict = dict(my_list)
And you are actually doing the same thing while calling zip
Also, if all keys are numbers and are not huge you can put all of them into array. Index would be the key. Though this solution depends on the actual task and might not be useful in some cases

Related

Need clarification on Sort by Frequency of second element in Tuple List program

from collections import Counter
test_list = [(6, 5), (2, 7), (2, 5), (8, 7), (9, 8), (3, 7)]
freq_2ndEle=Counter(val for key,val in test_list)
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
print(res)
Input : test_list = [(6, 5), (1, 7), (2, 5), (8, 7), (9, 8), (3, 7)]
Output : [(1, 7), (8, 7), (3, 7), (6, 5), (2, 5), (9, 8)]
Explanation : 7 occurs 3 times as 2nd element, hence all tuples with 7, are aligned first.
please clarify how the code is working especially, this part
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
I have confusion on ele:freq_2ndEle[ele[1]].
Here is an explanation - in the future, you should try following similar steps, including reading the documentation:
Counter takes an iterable or a map as an argument. In your case, val for key,val in test_list is an iterable. You fetch values from test_list and feed them to Counter.
You don't need the key, val semantics, it is confusing in this context, as it suggests you are looping through a dictionary. Instead, you are looping through a list of tuples so freq_2ndEle=Counter(tp[1] for tp in test_list) is much clearer - here you access the second tuple element, indexed with 1.
Counter gives you number of occurrences of each of the second tuple elements. If you print freq_2ndEle, you will see this:
Counter({7: 3, 5: 2, 8: 1}), which is a pair of how many times each second element appears in the list.
In the last step you're sorting the original list by the frequency of the second element using sorted,
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
So you take in test_list as an argument to sort, and then you specify the key by which you want to sort: in your case the key is the the time second tuple element occurred.
freq_2ndEle stores key-value pairs of second second element name:times it ocurred in test_list - it is a dictionary in a way, so you access it as you would access a dictionary, that is - you get the value that corresponds to ele[1] which is the (name) of the second tuple element. Name is not the base term, but I thought it may be clearer. The value you fetch with freq_2ndEle[ele[1]] is exactly the time ele[1] occurred in test_list
Lastly, you sort the keys, but in reverse order - that is, descending, highest to lowest, [(2, 7), (8, 7), (3, 7), (6, 5), (2, 5), (9, 8)] with the values that have the same keys (like 7 and 5) grouped together. Note, according to the documentation sorted is stable, meaning it will preserve the order of elements from input, and this is why when the keys are the same, you get them in the order as in test_list i.e. (2,7) goes first and (3,7) last in the "7" group.
freq_2ndEle is a dictionary that contains the second elements of the tuple as keys, and their frequencies as values. Passing this frequency as a return value of lambda in the key argument of the function sorted will sort the list by this return value of lambda (which is the frequency).
If your question is about how lambda works, you can refer to this brief explanation which is pretty simple.

All combinations of list elements in certain order

I have a list as follows:
((0,n1,n2,...,nX),(0,n1,n2,...,nY),(1,n1,n2,...,nZ),(2,n1,n2,...,nR),(2,n1,n2,...,nS))
I would like to return all possible combinations of list elements in such way:
(0,n1,n2,...,nX),(1,n1,n2,...,nZ),(2,n1,n2,...,nR)
(0,n1,n2,...,nY),(1,n1,n2,...,nZ),(2,n1,n2,...,nR)
(0,n1,n2,...,nX),(1,n1,n2,...,nZ),(2,n1,n2,...,nS)
(0,n1,n2,...,nY),(1,n1,n2,...,nZ),(2,n1,n2,...,nS)
So, I have understood and worked out that I need to iterate through elements and check first item of the list element to group elements by first item.
It could let me to do maybe a for loop? and try to manualy create all combinations?
However I wonder if there is any better approach?
I need to keep in mind that the elements must be in order ascending by first item of the elements --> 0, 1, 2
EDIT:
This is my list in other words:
((0,A), (0,B), (1,C), (2,D),(2,E))
how to return as follows:
(0,A),(1,C),(2,D)
(0,B),(1,C),(2,D)
(0,A),(1,C),(2,E)
(0,B),(1,C),(2,E)
?
The problem becomes easier if you change your data structures a bit. More specifically, just group all elements with the same "ID" in the same list.
For your example you have 3 lists:
a = [(0,n1,n2,...,nX),(0,n1,n2,...,nY)]
b = [(1,n1,n2,...,nZ)]
c = [(2,n1,n2,...,nR),(2,n1,n2,...,nS)]
Let me know if you have trouble separating the lists out like this, and I'll amend my answer.
Then you can use the itertools.product function to get all the combinations that you want.
import itertools
for i in itertools.product(a, b, c):
print i
Or if you want to see all the combinations as a list you can simply do:
list(itertools.product(a, b, c))
Similarly, you can use tuple() or set() if you want to see all the combinations as a tuple or a set.
EDIT:
If you to not have your elements already grouped together, and instead you have a flattened list(or tuple) of tuples you can create a list that groups tuples according to their "ID" (i.e., the first value of the simple tuples). Here's a function to do it. I assume there is no order in how the tuples are initially given (otherwise we can probably make this grouping more efficient)
def groupList(flatlist):
tempdict = {}
for element in flatlist:
id = element[0]
if id in tempdict:
tempdict[id].append(element)
else:
tempdict[id] = [element]
return list(tempdict.values())
Now you can used this "grouped" list to get all the combinations. Let's assume that you initial list is l, then you can do:
list(itertools.product(*groupList(l)))
Notice the * when passing the argument. This tells python to use the elements of this list as separate arguments to the function.
Example Input:
l = ((0, 10), (0, 20), (1, 30), (2, 40), (2, 50))
Example Output:
[((0, 10), (1, 30), (2, 40)), ((0, 10), (1, 30), (2, 50)), ((0, 20),
(1, 30), (2, 40)), ((0, 20), (1, 30), (2, 50))]

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.

How can I get the cartesian product of lists that are values in a dictionary? [duplicate]

This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 8 months ago.
I have a dictionary:
mydict = {'item1':[1,2,3],'item2':[10,20,30]}
I want to create the cartesian product of the two so that I get a tuple of each possible pair.
output: [(1,10),(1,20),(1,30),
(2,10),(2,20),(2,30),
(3,10),(3,20),(3,30)]
It seems like there would be a simple way to do this so that it extends if I have three items. Kind of like a dynamic number of loops. Feels like I am missing an obvious way to do this...
The itertools.product() function will do this:
>>> import itertools
>>> mydict = {'item1':[1,2,3],'item2':[10,20,30]}
>>> list(itertools.product(*mydict.values()))
[(10, 1), (10, 2), (10, 3), (20, 1), (20, 2), (20, 3), (30, 1), (30, 2), (30, 3)]
If you need to control the order of the resulting tuples, you can do
itertools.product(mydict['item1'], mydict['item2'])
You can also brute force it using two loops
mydict = {'item1':[1,2,3],'item2':[10,20,30]}
x = []
for i in mydict['item1']:
for j in mydict['item2']:
x.append((i,j))
All this code does is go through all of the item in mydict['item1'], then through each item in mydict['item2'], then appends a pair of each to a new list.
It will give you this result:
[(1, 10), (1, 20), (1, 30), (2, 10), (2, 20), (2, 30), (3, 10), (3, 20), (3, 30)]
You can use List Comprehensions:
[(i, j) for i in mydict['item1'] for j in mydict['item2']]
you could do two for loops.
- the first one would keep track of the index position of the first item list.
-The second loop would go through each item in the second.
- After it runs through all the items, the first for loop would increment to the next item in its list and the second loop will run through the second list again, etc.

Sorting dictionary using a tuple and operator.itemgetter

I am before my last milestone preparing suitable output. Its quite simple, I think, but my approach doesn't work:
Given an dictionary like
mydict = {x1: (val1, dist1, (lat1, lon1)), x2: (val2, dist2, (lat2, lon2)), ...}
I tried to sort this in a nested way in an array, first using the "values" and if equals, sorting for "dist".
However, I did my homework and tried it using this way:
import operator
s = sorted(mydict.iteritems(), key=operator.itemgetter(1))
The thing is that if the sort method would be appliable to tuples, it would be quite easy, because it's already in the right order.
Unfortunately I get:
'list' object is not callable
Do you have an idea?
Is it possible you overwrote the name sorted with a list value?
The thing is that if the sort method would be appliable to tuples, it would be quite easy
sorted() works perfectly fine on a list of tuples, in which case it uses a lexicographic ordering.
(a,b) ≤ (a′,b′) if and only if a < a′ or (a = a′ and b ≤ b′).
This can be expanded to any number of dimensions.
>>> sorted([(10, 1), (5, 3), (6, 5), (3, 2), (5, 10)])
[(3, 2), (5, 3), (5, 10), (6, 5), (10, 1)]

Categories