Sum list of list by first index - python

I want to "sum" two lists of lists by first index.
To give an example, I have L1 and L2:
L1=[[2,"word1"],[1,"word2"],[3,"word3"]]
L2=[[7,"word4"],[6,"word1"],[3,"word5"],[6,"word3"]]
and I want this as output:
L3=[[8,"word1"],[1,"word2"],[9,"word3"],[7,"word4"],[3,"word5"]]
Of course I know how to code this but not in a very elegant way, with some while loop, and I'm wondering if there is no simpler solution...
My code so far:
def sum_list(L1,L2):
word1=[x[1] for x in L1]
word2=[x[1] for x in L2]
score1=[x[0] for x in L1]
score2=[x[0] for x in L2]
word3=[]
L3=[]
i=0
while i<len(word1):
word3.append(word1[i])
if word1[i] not in word2:
L3.append([score1[i],word1[i]])
else:
L3.append([score1[i]+score2[word2.index(word1[i])],word1[i]])
i=i+1
i=0
while i<len(word2):
if word2[i] not in word3:
L3.append([score2[i],word2[i]])
i=i+1
return L3
Thanks

# Accumulate counts in a dict.
d = dict()
list(map(lambda p: d.__setitem__(p[1],d.setdefault(p[1], 0)+p[0]), L1))
list(map(lambda p: d.__setitem__(p[1],d.setdefault(p[1], 0)+p[0]), L2))
# Unpack the dict.
L3 = [[k, v] for k,v in d.items()]
print(L3)
A more verbose approach:
def accumulateInDict(d, l):
for pair in l:
key = pair[1]
count = d.get(key, 0)
d[key] = count + pair[0]
# Accumulate counts in a dict.
d = dict()
accumulateInDict(d, L1)
accumulateInDict(d, L2)
# Unpack the dict.
L3 = [[k, v] for k,v in d.items()]
print(L3)

You could use a Counter for that.:
from collections import Counter
L1 = [[2, "word1"], [1, "word2"], [3, "word3"]]
L2 = [[7, "word4"], [6, "word1"], [3, "word5"], [6, "word3"]]
L1_reversed = [l[::-1] for l in L1]
L2_reversed = [l[::-1] for l in L2]
L1_counter = Counter(dict(L1_reversed))
L2_counter = Counter(dict(L2_reversed))
L3_counter = L1_counter + L2_counter
print(L3_counter)
Gives:
Counter({'word3': 9, 'word1': 8, 'word4': 7, 'word5': 3, 'word2': 1})
And if you want to have your list of lists back:
L3 = [[value, key] for key, value in L3_counter.items()]
print(L3)
Which gives:
[[8, 'word1'], [1, 'word2'], [9, 'word3'], [7, 'word4'], [3, 'word5']]
The code is a bit convoluted, to change the data in the needed structure. But maybe you'd want to rethink about how you keep the data anyways as a list of list is not necessarily the best structure to represent such data. A dict would be the better representation here (no duplicates, and directly indexable by key).

Related

How do I raise list element in dict value to power of x?

I am a beginner in Python and have several exercises to resolve.
One of these is:
"Define a dictionary w/ keys "abc", "xyz" and values [1, 2, 3] and [9, 10, 11];
iterate over all values (lists) and raise to the power of 4 each element of each list and print to screen"
...and I am bit lost. I could define a function that raises the power of each element in a list, but I do not know how to do it in a dictionary :(
This is where I am stuck:
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
for x in dex.values():
print(x)
Since it's nested you could use a loop in a loop to get each item of each list, like this:
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
for x in dex.values():
for el in x:
print(el**4)
or using dict and list comprehension:
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
dex = {k: [el**4 for el in v] for k, v in dex.items()}
print(dex)
This way should work, if you can use dict comprehensions. It uses map, which applies a function to each elem in a list.
my_dict = {"abc": [1, 2, 3], "xyz": [9, 10, 11]}
new_dict = {key: list(map(lambda x: x ** 4, val)) for key, val in my_dict.items()}
Here, we map a function that raises each item in the list to a power.
Depending on how you want to present the output, this might work for you:
dex = {"abc": [1,2,3], "xyz": [9,10,11]}
print([[e**4 for e in lst] for lst in dex.values()])
Output:
[[1, 16, 81], [6561, 10000, 14641]]
This should work :
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
def print_exp (dic) :
for i,j in dic.items() :
if isinstance(j,list):
for n in j :
print(n**4)
print_exp(dex)
This one is with a function definition.
Without function definition you can achieve this by :
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
for i,j in dex.items() :
if isinstance(j,list):
for n in j :
print(n**4)
Since the index (or the power) stays constant, the magic method __rpow__ can be used to chain the operations: a**4 <--> int.__pow__(a, 4) <--> int.__rpow__(4, a)
dex = {"abc":[1,2,3],"xyz":[9,10,11]}
pows = [list(map(int(4).__rpow__, l)) for l in dex.values()]
print(pows)
Output
[[1, 16, 81], [6561, 10000, 14641]]

how to get all possible key-value pairs from python dictionary?

d = {"a":[1,2,3], "b":4}
I'm trying to create a nested list from d containing all pairs of key-value:
[["a",1],["a",2],["a",3],["b",4]]
Should I be using list comprehensions here, or is there a more pythonic way?
You can use a list comprehension:
d = {"a":[1,2,3], "b":4}
r = [[a, i] for a, b in d.items() for i in (b if isinstance(b, list) else [b])]
Output:
[['a', 1], ['a', 2], ['a', 3], ['b', 4]]
You can't use a list comprehension because it has to map from one item to another. You are intending to create more items than exist in the dict:
d = {"a":[1,2,3], "b":4}
result = []
for k,v in d.items():
if isinstance(v, list):
for item in v:
result.append([k,item])
else:
result.append([k,v])
def di(my_dictionary):
for key in my_dictionary:
if type(my_dictionary[key]) == list:
for item in my_dictionary[key]:
yield [key,item]
else:
yield [key,my_dictionary[key]]
and just use it by
d = {"a":[1,2,3], "b":4}
list(di(d))

Finding the elements in list such that elements should not have similar numbers

Consider a list = [23,52,44,32,78]
23,52,32 all these elements have at least one digit common so the set i want to filter is [44,78] as they don't have any common numbers.
Another example: [52,12,255,211,223,123,64,87,999] would be filtered as [64,87,999]
My current idea is to convert all the numbers into list like [2,3],[5,2]... and take a intersection of those but i couldn't understand how to compare all these sub-lists and filter out the desired numbers.
def convert_into_sublist(i):
sublist = [int(x) for x in str(i)]
def intersection(l1, l2):
l3 = [value for value in l1 if value in l2]
if(len(l3)==0):
return 1
handle the numbers as a list of characters and use set conversion and test if disjoint. Maybe not the most performant one-liner but works:
lst = [23,52,44,32,78]
# optional: remove duplicates:
lst = set(lst)
unique = [l for l in lst if all(set(str(x)).isdisjoint(str(l)) for x in lst if x != l)]
result:
>>> unique
[44, 78]
maybe slightly faster: convert to string once, process strings, convert back to integers in the end:
lst = [str(x) for x in lst]
unique = [int(l) for l in lst if all(set(x).isdisjoint(l) for x in lst if x != l)]
You can use Counter to find non-common digits:
from collections import Counter
from itertools import chain
from operator import itemgetter
lst = [23, 52, 44, 32, 78]
sets = [set(str(i)) for i in lst]
# [{'3', '2'}, {'5', '2'}, {'4'}, {'3', '2'}, {'7', '8'}]
c = Counter(chain.from_iterable(sets))
# Counter({'2': 3, '3': 2, '5': 1, '4': 1, '7': 1, '8': 1})
new_lst = []
for num, set_ in zip(lst, sets):
counts = itemgetter(*set_)(c)
if counts == 1 or set(counts) == {1}:
new_lst.append(num)
print(new_lst)
# [44, 78]

How to join values between sublists

I have a list with sublists, for example:
LA=[[1,2],[2,7],[4,5],[1,9],[6,5],[4,3],[2,1],[2,2]]
If the first element in each sublist is an ID, how do I join the ones with the same ID to get something like this:
LR=[[1,11],[2,10],[4,8],[6,5]]
I've tried using a for loop, but it's too long and not efficient.
You can use itertools.groupby:
import itertools
LA=[[1,2],[2,7],[4,5],[1,9],[6,5],[4,3],[2,1],[2,2]]
new_d = [[a, sum(i[-1] for i in list(b))] for a, b in itertools.groupby(sorted(LA), key=lambda x:x[0])]
Output:
[[1, 11], [2, 10], [4, 8], [6, 5]]
LA=[[1,2],[2,7],[4,5],[1,9],[6,5],[4,3],[2,1],[2,2]]
new_dict = {}
for (key, value) in LA:
if key in new_dict:
new_dict[key].append(value)
else:
new_dict[key] = [value]
for key, value in new_dict.items():
new_dict[key] = (sum(value))
dictlist = []
for key, value in new_dict.items():
temp = [key,value]
dictlist.append(temp)
print(dictlist)
will do the job too
You can do it just using list comprehensions:
LR = [[i,sum([L[1] for L in LA if L[0]==i])] for i in set([L[0] for L in LA])]
Gives the desired result.
To break this down a bit set([L[0] for L in LA]) gives a set (with no repeats) of all of the ID's, then we simply itterate over that set and sum the values which also have that ID.
Grouping with collections.defaultdict() is always straightforward:
from collections import defaultdict
LA = [[1,2],[2,7],[4,5],[1,9],[6,5],[4,3],[2,1],[2,2]]
# create defaultdict of list values
d = defaultdict(list)
# loop over each list
for sublist in LA:
# group by first element of each list
key = sublist[0]
# add to dictionary, each key will have a list of values
d[key].append(sublist)
# definitely can be more readable
result = [[key, sum(x[1] for x in [y for y in value])] for (key, value) in sorted(d.items())]
print(result)
Output:
[[1, 11], [2, 10], [4, 8], [6, 5]]

Python. Adding multiple items to keys in a dict

I am trying to build a dict from a set of unique values to serve as the keys and a zipped list of tuples to provide the items.
set = ("a","b","c")
lst 1 =("a","a","b","b","c","d","d")
lst 2 =(1,2,3,3,4,5,6,)
zip = [("a",1),("a",2),("b",3),("b",3),("c",4),("d",5)("d",6)
dct = {"a":1,2 "b":3,3 "c":4 "d":5,6}
But I am getting:
dct = {"a":1,"b":3,"c":4,"d":5}
here is my code so far:
#make two lists
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
# make a set of unique codes in the first list
routes = set()
for r in rtList:
routes.add(r)
#zip the lists
RtRaList = zip(rtList,raList)
#print RtRaList
# make a dictionary with list one as the keys and list two as the values
SrvCodeDct = {}
for key, item in RtRaList:
for r in routes:
if r == key:
SrvCodeDct[r] = item
for key, item in SrvCodeDct.items():
print key, item
You don't need any of that. Just use a collections.defaultdict.
import collections
rtList = ["EVT","EVT","EVT","EVT","EVT","EVT","EVT","HIL"]
raList = ["C64G","C64R","C64O","C32G","C96G","C96R","C96O","RA96O"]
d = collections.defaultdict(list)
for k,v in zip(rtList, raList):
d[k].append(v)
You may achieve this using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
which will return value of my_dict as:
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
OR, use collections.defaultdict as mentioned by TigerhawkT3.
Issue with your code: You are not making the check for existing key. Everytime you do SrvCodeDct[r] = item, you are updating the previous value of r key with item value. In order to fix this, you have to add if condition as:
l1 = ("a","a","b","b","c","d","d")
l2 = (1,2,3,3,4,5,6,)
my_dict = {}
for i, j in zip(l1, l2):
if i in my_dict: # your `if` check
my_dict[i].append(j) # append value to existing list
else:
my_dict[i] = [j]
>>> my_dict
{'a': [1, 2], 'c': [4], 'b': [3, 3], 'd': [5, 6]}
However this code can be simplified using collections.defaultdict (as mentioned by TigerhawkT3), OR using dict.setdefault method as:
my_dict = {}
for i, j in zip(l1, l2):
my_dict.setdefault(i, []).append(j)
In dicts, all keys are unique, and each key can only have one value.
The easiest way to solve this is have the value of the dictionary be a list, as to emulate what is called a multimap. In the list, you have all the elements that is mapped-to by the key.
EDIT:
You might want to check out this PyPI package: https://pypi.python.org/pypi/multidict
Under the hood, however, it probably works as described above.
Afaik, there is nothing built-in that supports what you are after.

Categories

Resources