Is there a way I can multiply the elements of a counter object by their count?
For example, if I were to multiply the elements of this:
Counter({5: 3, 6: 2, 8: 1})
I would get
{15, 12, 8}
Try to convert Counter object to list of tuples (also set is impossible for being ordered so use list:
>>> c=Counter({5: 3, 6: 2, 8: 1})
>>> [x*y for x,y in c.items()]
[15, 12, 8]
>>>
You can use a list comprehension as per #U9-Forward's solution.
An alternative functional solution is possible with operator.mul and zip:
from collections import Counter
from operator import mul
c = Counter({5: 3, 6: 2, 8: 1})
res = list(map(mul, *zip(*c.items())))
# [15, 12, 8]
If you really need a set, wrap map with set instead of list. The difference is set is an unordered collection of unique items, while list is an ordered collection with no restriction on duplicates.
Related
I have a numeric list a and I want to output a list with the hierarchical position of every element in a (0 for the highest value, 1 for the second-highest, etc).
I want to know if this is the most Pythonic and efficient way to do this. Perhaps there is a better way?
a = [3,5,6,25,-3,100]
b = sorted(a)
b = b[::-1]
[b.index(i) for i in a]
#ThierryLathuille's answer works only if there are no duplicates in the input list since the answer relies on a dict with the list values as keys. If there can be duplicates in the list, you should sort the items in the input list with their indices generated by enumerate, and map those indices to their sorted positions instead:
from operator import itemgetter
mapping = dict(zip(map(itemgetter(0), sorted(enumerate(a), key=itemgetter(1), reverse=True)), range(len(a))))
mapping becomes:
{5: 0, 3: 1, 2: 2, 1: 3, 0: 4, 4: 5}
so that you can then iterate an index over the length of the list to obtain the sorted positions in order:
[mapping[i] for i in range(len(a))]
which returns:
[4, 3, 2, 1, 5, 0]
You could also you numpy.argsort(-a) (-a because argsort assumes ascending order). It could have better performance for large arrays (though there's no official analysis that I know of).
One problem with your solution is the repeated use of index, that will make your final comprehension O(n**2), as index has to go over the sorted list each time.
It would be more efficient to build a dict with the rank of each value in the sorted list:
a = [3,5,6,25,-3,100]
ranks = {val:idx for idx, val in enumerate(sorted(a, reverse=True))}
# {100: 0, 25: 1, 6: 2, 5: 3, 3: 4, -3: 5}
out = [ranks[val] for val in a]
print(out)
# [4, 3, 2, 1, 5, 0]
in order to have a final step in O(n).
First, zip the list with a with range(len(a)) to create a list of tuples (of element and their positions), sort this list in reverse order, zip this with range(len(a)) to mark the positions of each element after the sort, now unsort this list (by sorting this based on the original position of each element), and finally grab the position of each element when it was sorted
>>> a = [3,5,6,25,-3,100]
>>> [i for _,i in sorted(zip(sorted(zip(a, range(len(a))), reverse=True), range(len(a))), key=lambda t:t[0][1])]
[4, 3, 2, 1, 5, 0]
I have a list of elements, lets say:
y = [1, 3, 1, 5, 1]
And I would like to create a dictionary where:
Keys: are the elements in y
Values: is a list of the elements that appear before the Key in y
I attempted the following comprehension.
a={elem:y[i] for i, elem in enumerate(y[1:])}
However, since the value field in the dictionary is not a list, it only keeps the previous element in the last occurrence of the key.
In other words, for this example I get the following:
{3: 1, 1: 5, 5: 3}
Is there a way to do so using comprehensions ?
Note: I forgot to add the desired result.
{3: [1], 1: [3,5], 5: [1]}
Your keys are duplicated, so you cannot create a dictionary with them (you'll lose the first elements).
So comprehensions are difficult to use (and inefficient, as stated by other comprehension answers here) because of the accumulation effect that you need.
I suggest using collections.defaultdict(list) instead and a good old loop:
import collections
y = [1, 3, 1, 5, 1]
d = collections.defaultdict(list)
for i,x in enumerate(y[1:]):
d[x].append(y[i]) # i is the index of the previous element in y
print(d)
result:
defaultdict(<class 'list'>, {1: [3, 5], 3: [1], 5: [1]})
Use enumerate and set operations.
{value: set(y[:i]) - {value} for i, value in enumerate(y)}
Out: {1: {3, 5}, 3: {1}, 5: {1, 3}}
It's a bit ugly and inefficient because in your example it works out a new answer each time it encounters 1, but it works out right because the final time it does this is the final time it encounters 1.
Just for the fun of it. Here's a comprehension.
a = {y[i]: [y[x-1] for x in range(len(y)) if y[x]==y[i]] for i in range(1, len(y))}
>> {3: [1], 1: [3,5], 5: [1]}
Just note that it's too long and inefficient to be allowed in any practical program.
Using the defaultdict as Jean-François Fabre suggested in his answer below should be the proper way.
I want to dynamically use sets to find common entires in lists. If I have a list of list that could contain any number of lists how can I go about find all the common occurrences in all the lists. I have thought about enumerating the list and storing each nested list in its own variable but then I am not sure how to compare all the individual lists.
Example of List:
l = [[1,2,3,4,], [3,6,4,2,1], [6,4,2,6,7,3]]
I want to do something like this but dynamic so it can accept any number of lists:
common = set(l[0]) & set(l[1]) & set(l[2])
Use reduce, with a lambda for
>>> l = [[1,2,3,4,], [3,6,4,2,1], [6,4,2,6,7,3]]
>>> from functools import reduce
>>> common = reduce(lambda l1,l2: set(l1) & set(l2), l)
>>> print(common)
{2, 3, 4}
Or, as a slightly modified version of #tobias_k's solution (as pointed in the comment), you can do it without lambda as
>>> common = reduce(set.intersection, [set(l[0])] + l[1:]))
You can use set.intersection:
set.intersection(*(set(ls) for ls in l)) #evaluates to {2, 3, 4}
You can use reduce from functools package:
from functools import reduce
l = [[1, 2, 3, 4], [3, 6, 4, 2, 1], [6, 4, 2, 6, 7, 3]]
print(reduce(set.intersection, map(set, l)))
Output:
{2, 3, 4}
This question was previously asked here with an egregious typo: Counting "unique pairs" of numbers into a python dictionary?
This is an algorithmic problem, and I don't know of the most efficient solution. My idea would be to somehow cache values in a list and enumerate pairs...but that would be so slow. I'm guessing there's something useful from itertools.
Let's say I have a list of integers whereby are never repeats:
list1 = [2, 3]
In this case, there is a unique pair 2-3 and 3-2, so the dictionary should be:
{2:{3: 1}, 3:{2: 1}}
That is, there is 1 pair of 2-3 and 1 pair of 3-2.
For larger lists, the pairing is the same, e.g.
list2 = [2, 3, 4]
has the dicitonary
{2:{3:1, 4:1}, 3:{2:1, 4:1}, 4:{3:1, 2:1}}
(1) Once the size of the lists become far larger, how would one algorithmically find the "unique pairs" in this format using python data structures?
(2) I mentioned that the lists cannot have repeat integers, e.g.
[2, 2, 3]
is impossible, as there are two 2s.
However, one may have a list of lists:
list3 = [[2, 3], [2, 3, 4]]
whereby the dictionary must be
{2:{3:2, 4:1}, 3:{2:2, 4:1}, 4:{2:1, 3:1}}
as there are two pairs of 2-3 and 3-2. How would one "update" the dictionary given multiple lists within a list?
EDIT: My ultimate use case is, I want to iterate through hundreds of lists of integers, and create a single dictionary with the "counts" of pairs. Does this make sense? There might be another data structure which is more useful.
For the nested list example, you can do the following, making use of itertools.permutations and dict.setdefault:
from itertools import permutations
list3 = [[2, 3], [2, 3, 4]]
d = {}
for l in list3:
for a, b in permutations(l, 2):
d[a][b] = d.setdefault(a, {}).setdefault(b, 0) + 1
# {2: {3: 2, 4: 1}, 3: {2: 2, 4: 1}, 4: {2: 1, 3: 1}}
For flat lists l, use only the inner loop and omit the outer one
For this example I'll just use a list with straight numbers and no nested list:
values = [3, 2, 4]
result = dict.from_keys(values)
for key, value in result.items():
value = {}
for num in values:
if num != key:
value[num] = 1
This creates a dict with each number as a key. Now in each key, make the value a nested dict who's contents are num: 1 for each number in the original values list if it isn't the name of the key that we're in
use defaultdict with permutations
from collections import defaultdict
from itertools import permutations
d = defaultdict(dict)
for i in [x for x in permutations([4,2,3])]:
d[i[0]] = {k: 1 for k in i[1:]}
output is
In [22]: d
Out[22]: defaultdict(dict, {2: {3: 1, 4: 1}, 4: {2: 1, 3: 1}, 3: {2: 1, 4: 1}})
for inherit list of lists https://stackoverflow.com/a/52206554/8060120
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
In Python, how to I iterate over a dictionary in sorted order?
I need help in dictionaries. I have two dictionaries, and I want to add the values of identical keys in those two dictionaries. I need to make a list of summing the values that has the same key. I did the list but those values that their keys are the only ones in the two dictionaries are added after finishing all calculations. What I mean is:
dectionary1= {8: 2, 0: 6, 2: 5, 3: 34}
dectionary2= {8: 6, 1: 2, 3: 2}
My list must be:
summing= [6, 2, 5, 36, 8]
since it will take 0 and check whether there is 0 in dectionary 2, and then it will TAKE 1 (NOT 2) and check whether it's found in dectionary 1 in order to order the list.
I got this so far:
summing=[8, 6, 5, 36, 2]
Here it initially takes key (8) not (0)!! I want it to be in order.
To see my code, that what I got so far:
dic1= {8: 2, 0: 6, 2: 5, 3: 34}
dic2= {8: 6, 1: 2, 3: 2}
p=[]
for x in dic1:
if x in dic2:
g=dic1[x]+dic2[x]
p=p+[g]
else:
p=p+[dic1[x]]
for m in dic2:
if m in dic1:
p=p
else:
p=p+[dic2[m]]
I think if I can make the dictionaries ascendingly ordered, it will be much easier, but how?
My python is Wing IDE 3.2
Thank you
You have two options here, one is to use collections.OrderedDict(), but I think the easier option is simply to do it this way:
[dic1.get(x, 0)+dic2.get(x, 0)for x in sorted(dic1.keys() | dic2.keys())]
We first make a set of any keys in either of the dictionaries, sort this into the right order, and then loop over it with a list comprehension, adding the two values (or 0 if the value doesn't already exist).
>>> dic1= {8: 2, 0: 6, 2: 5, 3: 34}
>>> dic2= {8: 6, 1: 2, 3: 2}
>>> [dic1.get(x, 0)+dic2.get(x, 0)for x in sorted(dic1.keys() | dic2.keys())]
[6, 2, 5, 36, 8]
Note that this only works in 3.x, where dict.keys() returns a set-like dictionary view. If you want to do this in python 2.7.x, use dict.viewkeys() instead, earlier than that, set(dict.iterkeys()) would be optimal.