So there are two tasks that are to be performed simultaneously on a dictionary.
Sort the dictionary and extract the top 10 keys along with their values
Ignore keys which have a certain value while reporting top 10
For e.g.
my_dict = { 'abc': 10, 'def':20, 'ghi':100, 'jkl':30, 'mno':101}
So, if I want top 3 while ignoring keys with value 100 and 101 is
result_top3 = [ ('jkl',30), ('def',20), ('abc',10)]
Right now I am using the following :
my_result = dict(Counter(my_dict).most_common()[:3])
but it has two problems:
I don't know how to add a filter in my expression to ignore certain values
It returns a dictionary, in which the keys may be unsorted although they would be top 10 values.
I was hoping if there was a way to do it in one go, or a more Pythonic and efficient way instead of doing it in 2 steps, like removing the keys I don't want and then sorting.
EDIT : It is not necessary to sort the complete dictionary. I just need to extract the top 10 results along with their values.
to filter data
[items for items in my_dict.items() if items[1] < 100]
to sort dict by key value
sorted(my_dict.items(), key=lambda x: -x[1])
and full your solution
sorted([items for items in my_dict.items() if items[1] < 100], key=lambda x: -x[1])[:3]
Do this-
>>> my_dict = { 'abc': 10, 'def':20, 'ghi':100, 'jkl':30, 'mno':101}
>>> dict_tuple = my_dict.items()
>>> print dict_tuple
[('jkl', 30), ('abc', 10), ('ghi', 100), ('def', 20), ('mno', 101)]
>>> dict_tuple.sort(key=lambda x: x[1])
>>> print dict_tuple
[('abc', 10), ('def', 20), ('jkl', 30), ('ghi', 100), ('mno', 101)]
>>> print dict(dict_tuple[:3])
{'jkl': 30, 'abc': 10, 'def': 20}
Almost the same as #BearBrown's answer. But using built-in features and break it down, for doing it step-by-step:
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct 3 2017, 00:32:08)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.0.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from collections import OrderedDict
In [2]: my_dict = { 'abc': 10, 'def':20, 'ghi':100, 'jkl':30, 'mno':101}
# filter values out, can be `if v >= 100`(this is depends on condition)
In [3]: filtered_values = ((k, v) for k, v in my_dict.items() if v not in [100, 101])
In [4]: filtered_values
Out[4]: <generator object <genexpr> at 0x1060a9ca8>
In [5]: import operator
# sort by values(second element of key-value tuple) in reverse order
In [6]: top_three = sorted(filtered_values, key=operator.itemgetter(1), reverse=True)[:3]
In [7]: top_three
Out[7]: [('jkl', 30), ('def', 20), ('abc', 10)]
In [8]: OrderedDict(top_three)
Out[8]: OrderedDict([('jkl', 30), ('def', 20), ('abc', 10)])
In the end you will get OrderedDict(dict that have order) as you wanted.
You can do it stepwise:
my_dict = { 'abc': 10, 'def':20, 'ghi':100, 'jkl':30, 'mno':101}
filterIt = [(x[1],x[0]) for x in my_dict.items() if x[1] not in [101,100]]
sortOfSorted = sorted(filterIt, reverse = True)
print (my_dict)
print(filterIt)
print (sortOfSorted)
The result is a list of tuples with the "value" on [0] - no lambda needed for sorting that way as tuples get sorted by [0] first, then [1]
Dictionarys like sets are inherently unordered. And to get the top 10 out of anything you need to sort all of the items to find the biggest ones.
Output:
{'jkl': 30, 'abc': 10, 'ghi': 100, 'def': 20, 'mno': 101}
[(30, 'jkl'), (10, 'abc'), (20, 'def')]
[(30, 'jkl'), (20, 'def'), (10, 'abc')]
you can try:
operator.itemgetter(1) will sort dict by value; and operator.itemgetter(0) will sort dict by key
>>> import operator
>>> my_dict = { 'abc': 10, 'def':20, 'ghi':100, 'jkl':30, 'mno':101}
>>> sorted_my_dict = sorted(my_dict.items(), key=operator.itemgetter(1))
>>> sorted_my_dict
[('abc', 10), ('def', 20), ('jkl', 30), ('ghi', 100), ('mno', 101)]
>>> sorted_my_dict[:3]
[('abc', 10), ('def', 20), ('jkl', 30)]
Related
For example, I have an array of tuples.
l=[(456,33,1),
(556,22,1),
(123,33,2),
(557,32,2),
(435,21,2)]
I want make the arrays of lists by the last element in each tuple, so that
l=[[(456,33),
(556,22)],
[(123,33),
(557,32),
(435,21)]]
How could I do that? Is there any elegant way?
l = [(456, 33, 1), (556, 22, 1), (123, 33, 2), (557, 32, 2), (435, 21, 2)]
out = {}
for v in l:
out.setdefault(v[-1], []).append(v[:-1])
out = list(out.values())
print(out)
Prints:
[[(456, 33), (556, 22)],
[(123, 33), (557, 32), (435, 21)]]
Another way of doing this would be with itertools.groupby.
from itertools import groupby
from operator import itemgetter
res = [[x[:-1] for x in g] for _, g in groupby(sorted(l, key=itemgetter(2)), itemgetter(2))]
which produces the desired:
[[(456, 33), (556, 22)], [(123, 33), (557, 32), (435, 21)]]
Note that if you can guarantee that the original list l is sorted by the 3rd item in the tuples, you can replace sorted(l, key=itemgetter(2)) with just l.
An alternative attempt is using this:
l=[(456,33,1),
(556,22,1),
(123,33,2),
(557,32,2),
(435,21,2)]
dict_ = {}
for v in l:
val1, val2, id_ = v
dict_[id_] = [[val1, val2]] if id_ not in dict_ else dict_[id_] + [[val1, val2]]
l = [dict_[x] for x in dict_]
I have a dictionary like this,
{'A':[[1,30],[40,50],[60,79]]
'B':[[2,23],[26,43],[59,119]]
'C':[[1,100],[149,167],[199,250]]
... }
I had the MAX value which is 600. Is it possible to calculate the difference between each value in every list?
Finally, I can get a dictionary like this
{'A':[[31,39],[51,59],[80,600]]
'B':[[24,25],[44,58],[120,600]]
'C':[[101,148],[168,198],[251,600]]
...
}
Let me explain how final output comes.
The origin data is
'A':[[i1,i2],[i3,i4],[i5,i6]]
Max value is M,
For each list, final output will be like
'A':[[(i2)+1,(i3)-1],[(i4)+1,(i5)-1],[(i6)+1,M]]
It seems I need a for loop to get there. But I have no idea how to do this in dictionary.
You can try this:
d1 = {'A':[[1,30],[40,50],[60,79]],
'B':[[2,23],[26,43],[59,119]],
'C':[[1,100],[149,167],[199,250]]}
def split_l(iterable, n):
return [iterable[i:i+n] for i in range(0, len(iterable), n)]
d2 = {k:split_l([val + (-1)**idx for idx, val in enumerate(sum(v, [])[1:])] + [600], 2) for k,v in d1.items()}
Or in more readable way:
d2 = {}
for k, v in d1.items():
flat_v = sum(v, [])[1:]
for idx, __ in enumerate(flat_v):
flat_v[idx] += (-1)**idx
flat_v.append(600)
split_v = [flat_v[i:i+2] for i in range(0, len(flat_v), 2)]
d2[k] = split_v
Results:
import pprint
pprint.pprint(d2)
{'A': [[31, 39], [51, 59], [80, 600]],
'B': [[24, 25], [44, 58], [120, 600]],
'C': [[101, 148], [168, 198], [251, 600]]}
YOu can you itertools.chain
>>> from itertools import chain
>>> d = {'A':[[1,30],[40,50],[60,79]], 'B':[[2,23],[26,43],[59,119]],}
>>> for key in d:
... d[key] = zip(*[iter([each+((-1)**index) for index,each in enumerate(chain.from_iterable(d[key]))]+[600,])]*2)
...
>>> d
{'A': [(31, 39), (51, 59), (80, 600)], 'B': [(24, 25), (44, 58), (120, 600)]}
That is,
>>> chain.from_iterable(d['A'])
<itertools.chain object at 0x7f6a9dd69950>
>>> list(chain.from_iterable(d['A']))
[31, 39, 51, 59, 80, 600]
>>> iter(each for each in enumerate(chain.from_iterable(d[key])))
<generator object <genexpr> at 0x7f6a9dd804b0>
>>> zip(*[iter(each for each in enumerate(chain.from_iterable(d[key])))]*2)
[((0, 2), (1, 23)), ((2, 26), (3, 43)), ((4, 59), (5, 119))]
keep in mind that in python you can swap values of two variables this way:
a, b = b, a
so your problem can be solved like this:
def my_func(a_dict, max):
for row in a_dict.values():
row[0][0], row[0][1], row[1][0], row[1][1], row[2][0], row[2][1] = \
row[0][1]+1, row[1][0]-1, row[1][1]+1, row[2][0]-1, row[2][1]+1, max
One thing to notice is that there is no return .... dictionary is mutable, so any change to a_dict will retain.
After calling my_func, the dictionary passed to the function will contain the result.
update
#MaximTitarenko told me that the number of inner lists in each row(row=a list associated with a key of the dictionary)may vary.
so I wrote another script which works in that case:
def make_result(a_dict, max):
for row in a_dict.values():
for index in range(len(row)-1):
row[index][0] = row[index][1] + 1
row[index][1] = row[index+1][0] -1
row[-1][0] = row[-1][1] + 1
row[-1][1] = max
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
I have a list 'l' of tuples.
l = [('apple',4), ('carrot',2), ('apple',1), ('carrot',7)]
I want to arrange the first elements of tuples according to the values in ascending order.
The expected result is:
result = [('apple', (1,4)), ('carrot', (2,7))]
I tried as:
for x in l:
variables = list(set(x[0]))
I suppose that there is more better way of doing it. Any ideas please.
You could use a defaultdict to collect those values, and then get the items from the dictionary to get the desired result:
>>> l = [('apple',4), ('carrot',2), ('apple',1), ('carrot',7)]
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for k, v in l:
d[k].append(v)
>>> dict(d)
{'carrot': [2, 7], 'apple': [4, 1]}
>>> list(d.items())
[('carrot', [2, 7]), ('apple', [4, 1])]
In order to sort those sublists then, you could use a list comprehension:
>>> [(k, tuple(sorted(v))) for k, v in d.items()]
[('carrot', (2, 7)), ('apple', (1, 4))]
And if you want to sort that also by the “key”, just sort that resulting list using list.sort().
Here is my solution:
from collections import defaultdict
l = [('apple',4), ('carrot',2), ('apple',1), ('carrot',7)]
d = defaultdict(list)
for i, j in l:
d[i].append(j)
result = sorted([tuple([x, tuple(sorted(y))]) for x, y in d.items()])
print(result)
And here is the result:
[('apple', (1, 4)), ('carrot', (2, 7))]
Here's a one liner for you:
>>> a = [('apple',4), ('carrot',2), ('apple',1), ('carrot',7)]
>>> sorted([(n, tuple(sorted([e[1] for e in a if e[0] == n]))) for n in set(e for e,f in a)])
[('apple', (1, 4)), ('carrot', (2, 7))]
This sorts both the first element (apple, carrot, ...), and each second element ( (1,4) (2,7) ).
Note that #poke's solution does not sort it.
Say I have a list:
[(12,34,1),(123,34,1),(21,23,1)]
I want to remove the 1 from each tuple in the list so it becomes
[(12,34),(123,34),(21,23)]
You want to truncate your tuples, use a list comprehension:
[t[:-1] for t in listoftuples]
or, as a simple demonstration:
>>> listoftuples = [(12,34,1),(123,34,1),(21,23,1)]
>>> [t[:-1] for t in listoftuples]
[(12, 34), (123, 34), (21, 23)]
Tuples are immutable, so you can not remove an item. However, you can create a new tuple from the old tuple not including the elements you do not want to. So, to delete an arbitrary item from each tuple from a list of tuples, you can do:
def deleteItem(lst, toDel):
return [tuple(x for x in y if x != toDel) for y in lst]
Result:
>>> lst = [(12,34,1),(123,34,1),(21,23,1)]
>>> deleteItem(lst, 1)
[(12, 34), (123, 34), (21, 23)]
>>> a=[(12, 34, 1), (123, 34, 1), (21, 23, 1)]
>>> [filter (lambda a: a != 1, x) for x in a]
[(12, 34), (123, 34), (21, 23)]
THis will remove all 1 from the tuple irrespective of index
Since you can't change tuples (as they are immutable), I suggest using a list of lists:
my_list = [[12,34,1],[123,34,1],[21,23,1]]
for i in my_list:
i.remove(1)
return my_list
This returns: [[12, 34], [123, 34], [21, 21]].
python 3.2
1. [(i,v)for i,v,c in list1]
2. list(map(lambda x:x[:2],list1))