Referring to the below code, the first for loop can be easily used for the sorting in the dictionary and it works very well.
import operator
myExample = {'Item1': 3867, 'Item2': 20, 'Item3': 400, 'Item4': 100, 'Item5': 2870,
'Item6': 22, 'Item7': 528, 'Item8': 114}
for w in sorted(myExample, key=myExample.get, reverse=False):
print w, myExample[w]
print ("\n")
for w in sorted(myExample, key=operator.itemgetter(0)):
print w, myExample[w]
But somehow I was told by the other thread, it is advice to use operator.itemgetter(index) method to perform the sorting due to the efficiency reason. But the second for loop is never works in my case.
Perhaps I should go through the documentation first and this is what I get:
>>> itemgetter(1)('ABCDEFG')
'B'
>>> itemgetter(1,3,5)('ABCDEFG')
('B', 'D', 'F')
>>> itemgetter(slice(2,None))('ABCDEFG')
'CDEFG'
The example is simple, But to be honest, I don't know how to link this back to the dictionary case. How should I use the index inside the itemgetter and different index will have what kind of impact? I tried all index from 0 to 4 and none of them give me an ascending sorting result and error will occur starting from index 5.
In a document, there is a example for tuple case, but it's not works for the dictionary.
>>> inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
>>> getcount = itemgetter(1)
>>> map(getcount, inventory)
[3, 2, 5, 1]
>>> sorted(inventory, key=getcount)
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]
Back to the Origin, I still hope to understand how to use the index inside the itemgetter and what it does in different cases like tuple vs. dictionary vs. list vs. only a string vs. tuple inside a list, and etc.
Please advise.
Related
Given a list of iterables:
li = [(1,2), (3,4,8), (3,4,7), (9,)]
I want to sort by the third element if present, otherwise leave the order unchanged. So here the desired output would be:
[(1,2), (3,4,7), (3,4,8), (9,)]
Using li.sort(key=lambda x:x[2]) returns an IndexError. I tried a custom function:
def safefetch(li, idx):
try:
return li[idx]
except IndexError:
return # (ie return None)
li.sort(key=lambda x: safefetch(x, 2))
But None in sorting yields a TypeError.
Broader context: I first want to sort by the first element, then the second, then the third, etc. until the length of the longest element, ie I want to run several sorts of decreasing privilege (as in SQL's ORDER BY COL1 , COL2), while preserving order among those elements that aren't relevant. So: first sort everything by first element; then among the ties on el_1 sort on el_2, etc.. until el_n. My feeling is that calling a sort function on the whole list is probably the wrong approach.
(Note that this was an "XY question": for my actual question, just using sorted on tuples is simplest, as Patrick Artner pointed out in the comments. But the question is posed is trickier.)
We can first get the indices for distinct lengths of elements in the list via a defaultdict and then sort each sublist with numpy's fancy indexing:
from collections import defaultdict
# {length -> inds} mapping
d = defaultdict(list)
# collect indices per length
for j, tup in enumerate(li):
d[len(tup)].append(j)
# sort
li = np.array(li, dtype=object)
for inds in d.values():
li[inds] = sorted(li[inds])
# convert back to list if desired
li = li.tolist()
to get li at the end as
[(1, 2), (3, 4, 7), (3, 4, 8), (9,)]
For some other samples:
In [134]: the_sorter([(12,), (3,4,8), (3,4,7), (9,)])
Out[134]: [(9,), (3, 4, 7), (3, 4, 8), (12,)]
In [135]: the_sorter([(12,), (3,4,8,9), (3,4,7), (11, 9), (9, 11), (2, 4, 4, 4)])
Out[135]: [(12,), (2, 4, 4, 4), (3, 4, 7), (9, 11), (11, 9), (3, 4, 8, 9)]
where the_sorter is above procedure wrapped in a function (name lacks imagination...)
def the_sorter(li):
# {length -> inds} mapping
d = defaultdict(list)
# collect indices per length
for j, tup in enumerate(li):
d[len(tup)].append(j)
# sort
li = np.array(li)
for inds in d.values():
li[inds] = sorted(li[inds])
return li.tolist()
Whatever you return as fallback value must be comparable to the other key values that might be returned. In your example that would require a numerical value.
import sys
def safefetch(li, idx):
try:
return li[idx]
except IndexError:
return sys.maxsize # largest int possible
This would put all the short ones at the back of the sort order, but maintain a stable order among them.
Inspired by #Mustafa Aydın here is a solution in Pandas. Would prefer one without the memory overhead of a dataframe, but this might be good enough.
import pandas as pd
li = [(1,2), (3,4,8), (3,4,7), (9,)]
tmp = pd.DataFrame(li)
[tuple(int(el) for el in t if not pd.isna(el)) for t in tmp.sort_values(by=tmp.columns.tolist()).values]
> [(1, 2), (3, 4, 7), (3, 4, 8), (9,)]
I want to make a set of tuples in which the order of tuples shouldn't matter.
For eg.- If the tuples I want to add is :
[(1,2),(1,3),(2,1)]
It should output like this:
{(1,2),(1,3)}
Is there any efficient way of doing this in python?
You can apply sorted and then tuple, followed by conversion to set:
res = set(map(tuple, map(sorted, L)))
print(res)
{(1, 2), (1, 3)}
Explanation
There are a couple of good reasons why you should not convert each tuple to set as an initial step:
Tuples (1, 1, 2) and (1, 2) would become equal after conversion to set.
Even in the case where we are considering tuples of length 2, we would be adding an assumption that tuple({(1, 2)}) and tuple({(2, 1)}) are equal. While this may be true, it would be considered an implementation detail, since set is considered to be unordered.
Function composition
Function composition is not native to Python, but if you have access to the 3rd party toolz library you can avoid nested map:
from toolz import compose
tup_sort = compose(tuple, sorted)
res = set(map(tup_sort, L))
You can sort the tuples:
l = [(1,2),(1,3),(2,1)]
res = set(map(lambda x: tuple(sorted(x)), l))
print(res)
{(1, 2), (1, 3)}
The other answers all work! I'm just going to post mine here because I'm a beginner and I love to practice.
mainSet = set()
l = [(1,2),(1,3),(2,1)]
for i in l:
if tuple(sorted(i)) not in mainSet:
mainSet.add(tuple(sorted(i)))
print(mainSet)
Gives back
{(1, 2), (1, 3)}
Whether you want to use this or not is up to you! The other answers are much more shorter.
You can use comprehension, too:
l=[(1, 2), (1, 3), (2, 1)]
res={ tuple(sorted(t)) for t in l }
print(res)
{(1, 2), (1, 3)}
I want to take items from a list and put them into a dictionary.
Say we have the following
carList = set(zip(carWordList, carWordFreq))
note: I use set to remove duplicates
So carList would produce the following:
set([('merry', 3), ('cop', 25), ('completely', 21), ('jaw', 2), ('fiddle', 1), ('bright', 4), ('593', 1), ('asked', 22), ('additionally', 4), ('pretend', 1), ('beam', 4)])
Now I want to take the words (ex. 'merry') and make them keys in a dictionary (newDic) with the numbers as values.
Also, I want to use that new dictionary to create another dictionary (otherDic) that has two keys (one being the word (ex. 'merry') and another being "Car", which will take a value later
for key in newDic:
otherDic = [key]["Car"]
I tried to do the following:
for key in carList:
otherDic = [key]["Car"]
However, I get the following error:
TypeError: list indices must be integers, not str
When you do this
otherDic = [key]["Car"]
You are just creating a list [key] that contains only key, and then you are trying to index it with "Car" instead of with an integer, which is why you get the error.
Secondly, you can't start looping into this for key in newDic: without ever creating the newDic which I don't see you doing at any point.
Anyway, this is the wrong way to approach your problem. To turn your set into a dictionary you can simply do this:
my_dict = {key: value for key, value in carList}
That's called dictionary comprehension by the way. But as #Adam Smith pointed out, that is actually equivalent to
my_dict = dict(carList)
Which is simpler... But after that, I don't quite understand what you mean by creating another dict with 2 keys per value. You can't create a dict with 2 keys, that's not how they work. You could comment here on the desired output of this new dict and I will edit my answer.
You can use dictionary comprehension:
In [61]: l = set([('merry', 3), ('cop', 25), ('completely', 21), ('jaw', 2), ('fiddle', 1), ('bright', 4), ('593', 1), ('asked', 22), ('additionally', 4), ('pretend', 1), ('beam', 4)])
In [63]: d = {k:v for k,v in l}
In [64]: d
Out[64]:
{'593': 1,
'additionally': 4,
'asked': 22,
'beam': 4,
'bright': 4,
'completely': 21,
'cop': 25,
'fiddle': 1,
'jaw': 2,
'merry': 3,
'pretend': 1}
Say I have this:
d={'a':[(1,2),(3,4)],'b':[(9,2),(5,4)],'c':[(2,2),(7,7)]}
where d is a dictionary in python. I'd like to get random tuples out of this corresponding to a particular key using the random.choice() method.
This is what I'm doing and it's not working:
random.choice(d['a'].values())
d['a'] is already a list, so you don't need to call .values() on it.
import random
d = {
'a': [(1, 2), (3, 4)],
'b': [(9, 2), (5, 4)],
'c': [(2, 2), (7, 7)],
}
print(random.choice(d['a']))
If you're just trying to get a random tuple out of key you pick, you've written too much:
random.choice(d['a'])
(Also NB: You'll need quotes around the keys in the dictionary. Right now you're using, e.g., the undefined variable a instead of the string 'a'.)
I'm trying to compare things in list, tuple, etc. and I'm wondering how we specify what we want to compare. I want to sort a list: [('A',(6,2,1,3)), ('B',(4,5,9,3)), ('C',(1,2,3,8))] by the last number, and if the last number is equal, then sort by the 3rd number. However, I'm unsure how to approach this. I used lambda to sort by the last number, but when the last numbers are equal, python automatically sorts by the first number.
Using the lambda, create a key which is a tuple of last number and third number:
mylist = [('B',(4,5,9,3)), ('C',(1,2,3,8)), ('A',(6,2,1,3))]
mylist.sort(key=lambda x:(x[1][-1], x[1][2]))
Outputs:
[('A', (6, 2, 1, 3)), ('B', (4, 5, 9, 3)), ('C', (1, 2, 3, 8))]
You basically want to sort by the last element in each tuple, reversed. Python translates that english to code pretty well:
sorted(li,key=lambda x: tuple(reversed(x[-1])))
Out[4]: [('A', (6, 2, 1, 3)), ('B', (4, 5, 9, 3)), ('C', (1, 2, 3, 8))]