Looping over list elements without for loop - python

I have a Python dictionary with multiple values stored as a list like this-
{'a': [1, 2, 3], 'b': [2, 3, 4], 'c': [3, 4, 5]}
I wish to create a dictionary of lists where each values becomes a key and stores the list as a value like this
if __name__=='__main__':
x={'a':[1,2,3],'b':[2,3,4],'c':[3,4,5]}
d=dict()
for key,value in x.items():
for i in value:
if i not in list(d.keys()):
d[i]=value
else:
d[i].extend(value)
print(d)
I get the following output-
{1: [1, 2, 3, 2, 3, 4], 2: [1, 2, 3, 2, 3, 4], 3: [3, 4, 5, 1, 2, 3, 2, 3, 4, 2, 3, 4], 4: [3, 4, 5, 1, 2, 3, 2, 3, 4, 2, 3, 4], 5: [3, 4, 5, 1, 2, 3, 2, 3, 4, 2, 3, 4]}
I wish for the output to be like this-
{1: [1, 2, 3], 2: [2, 3, 4, 1, 2, 3], 3: [2, 3, 4, 3, 4, 5, 1, 2, 3], 4: [2, 3, 4, 3, 4, 5], 5: [3, 4, 5]}
Where is the error in my code?
I wish to avoid nested for loops as I have to iterate over a large number of values (x dictionary keys and list elements). Is there a better way to iterate over each list value without using nested loops? Should I redo the way I've stored the values (some other data type besides dictionary of lists)?
I'm looking for a solution that is computationally inexpensive in terms of time and maybe space too.
Edit:
By making a copy of the list, the code returns correct output-
if __name__=='__main__':
x={'a':[1,2,3],'b':[2,3,4],'c':[3,4,5]}
d=dict()
for key,value in x.items():
for i in value:
if i not in list(d.keys()):
d[i]=list(value)
else:
d[i].extend(value)
print(d)

You could use defaultdict:
from collections import defaultdict
x={'a':[1,2,3],'b':[2,3,4],'c':[3,4,5]}
d=defaultdict(list)
for key,value in x.items():
for i in value:
d[i] += value
Or
for value in x.values():
for i in value:
d[i] += value

Related

Python: How to aggregate and count identical values in a Dictionary

I'm using a defaultdict from Python's collections:
from collections import defaultdict
data = defaultdict(list)
Within the dictionary I have a set of key/list. Example:
{1: [1, 6, 3, 4, 5], 2: [1, 3, 2, 4, 5], 3: [1, 6, 3, 4, 5]})
I'm looking for a way to count how many times each list (identical order and content) is found in the dictionary. Basically, I need to aggregate each list with a counter.
For example, the combination [1, 6, 3, 4, 5] is found 2 times.
Is there any helper class/function that can do it? Other than that, I'd just create a double for loop across the dictionary.
Thanks!
Try this:
from collections import Counter
data = defaultdict(list, {1: [1, 6, 3, 4, 5], 2: [1, 3, 2, 4, 5], 3: [1, 6, 3, 4, 5]})
c = Counter(map(tuple, data.values()))
print(c)
Counter({(1, 6, 3, 4, 5): 2, (1, 3, 2, 4, 5): 1})
H = {1: [1, 6, 3, 4, 5], 2: [1, 3, 2, 4, 5], 3: [1, 6, 3, 4, 5]}
occurences = dict()
for i in H.keys() :
k = 0
for j in H.keys():
if H[j] == H[i] :
k += 1
if i not in occurences.keys():
occurences[i] = k
Use collections.Counter
>>> from collections import Counter
>>> d = {1: [1, 6, 3, 4, 5], 2: [1, 3, 2, 4, 5], 3: [1, 6, 3, 4, 5]}
>>> print(Counter(tuple(l) for l in d.values())
Counter({(1, 6, 3, 4, 5): 2, (1, 3, 2, 4, 5): 1})
You'll have to convert your lists to tuples, because Counters can't count unhashable (mutable) types.

python updating global dict inside recursive function

I am trying to find all permutations of elements in a list and add it to a global dictionary
Code:
outp={}
k=0
def func(i,arr):
global outp
global k
arr=arr.copy()
for j in range(i,len(list)):
arr[i],arr[j] = arr[j],arr[i]
if i!=j or i==0:
k=k+1
print("\n\n",arr,k)
outp[k]=arr
print("\n",outp)
func(i+1,arr)
list = [1,2,3,8]
func(0,list)
Output below:
Till 4th element it updated correctly. During 5th element, it updated both 5th and 3rd element in the dictionary. I don't know why it is happening. Kindly help
[1, 2, 3, 8] 1
{1: [1, 2, 3, 8]}
[1, 2, 8, 3] 2
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3]}
[1, 3, 2, 8] 3
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 3, 2, 8]}
[1, 3, 8, 2] 4
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 3, 2, 8], 4: [1, 3, 8, 2]}
[1, 8, 2, 3] 5
{1: [1, 2, 3, 8], 2: [1, 2, 8, 3], 3: [1, 8, 2, 3], 4: [1, 3, 8, 2], 5: [1, 8, 2, 3]}
You need to place a copy of the array in the dictionary:
outp[k] = arr.copy()
This would be a better way to copy list to a new list.
arr=arr[:] .
https://repl.it/repls/BronzeYellowConversion

Count odds in list of lists

What would be the shortest way to count the number of odd numbers in a list of lists like this with arbitrary dimensions, not necessarily 5x5:
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
I tried, but i'd guess there's shorter:
counter = 0
for row in list_of_lists:
for i in row:
if i % 2 != 0:
counter += 1
print(counter)
If you always have one level of flat lists inside the main list you can use an inner loop to flatten, summing the result of each i % 2 which will be 1 for odd and 0 for even numbers:
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
print(sum(i % 2 for sub in list_of_lists for i in sub))
Or use itertools.chain to do the flattening:
from itertools import chain
print(sum(i % 2 for i in chain(*list_of_lists)))
If you had arbitrary nesting, recursion would be an easy way to approach the problem:
def flat(lst):
for i in lst:
if isinstance(i, list):
for j in flat(i):
yield j % 2
else:
yield i % 2
print(sum(flat(list_of_lists)))
The numpy way of counting for a contrast:
import numpy as np
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
l = np.array(list_of_lists)
print len(l[l%2!=0])
l[l%2!=0] returns all the elements that satisfy the condition l%2!=0 and len() counts it.
PS : This of course assumes that the list_of_lists is rectangular. For a solution that allows different length for each inner-list, see Padraic's answer.

Can I remove a single value from a dictionary?

I have a dictionary and I want to remove a single value from a key:values combination.
For example, when having the following dictionary:
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
I'd like to remove the key:value 1:2, so that the dictionary becomes:
{1: [3, 4, 7], 2: [1, 3, 4]}
Is this doable?
You have a dict that holds lists.
The lists can be manipulated in the usual manner
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
d[1].remove(2)
print(d)
# {1: [3, 4, 7], 2: [1, 3, 4]}
Well, first find a reference to list, then remove an item with value 2 from list, so:
d[1].remove(2)
d = {1: [2, 3, 4, 7], 2: [1, 3, 4]}
d[1].remove(2)
print d

Mapping list - list as dictionary in python

Not to be confused with this question in Stackoverflow.
I have a list called a = [2, 3, 4, 1]
I have some function say func(), which is as follows:
def func(a):
o = []
n = len(a)
for i in range(n):
x=a[:]
x[i],x[(i+1)%n] = x[(i+1)%n],x[i]
o.append(x)
return o
and func(a) produces another list as follows:
[[3, 2, 4, 1], [2, 4, 3, 1], [2, 3, 1, 4], [1, 3, 4, 2]]
Now I want to map the output list to the list from which it is generated. So, how to generate a dictionary in the following format:
a : o
key : value1, value2........last value
[2, 3, 4, 1] : [3, 2, 4, 1], [2, 4, 3, 1], [2, 3, 1, 4], [1, 3, 4, 2]
Keys in a dictionary cannot be mutable type. You can have a tuple instead. That is
(2, 3, 4, 1) : [3, 2, 4, 1], [2, 4, 3, 1], [2, 3, 1, 4], [1, 3, 4, 2]
This can be done as
def func(a):
o = []
n = len(a)
for i in range(n):
x=a[:]
x[i],x[(i+1)%n] = x[(i+1)%n],x[i]
o.append(x)
return {tuple(a):o}
For example func([2,3,4,1]) will now return
{(2, 3, 4, 1): [[3, 2, 4, 1], [2, 4, 3, 1], [2, 3, 1, 4], [1, 3, 4, 2]]}
Also note: according to documentation :
The only types of values not acceptable as keys are values containing
lists or dictionaries or other mutable types that are compared by
value rather than by object identity, the reason being that the
efficient implementation of dictionaries requires a key’s hash value
to remain constant
POST COMMENT EDIT
You can access the keys directly usin [] notation.
E.g:
l = [2,3,4,1]
a = func(l)
print (a[tuple(l)])
This will print the list of values.
Or you can loop through the entire dictionary
for i in a.items():
for j in i:
print (j)
This will print
[3, 2, 4, 1]
[2, 4, 3, 1]
[2, 3, 1, 4]
[1, 3, 4, 2]

Categories

Resources