I have three types of element: a dict, a list with one dict, and a list with multiple dicts.
a = {"foo":1}
b = [{"foo":2}]
c = [{"foo":3}, {"foo":4}]
list = [a, b, c]
I want to be print all four values. The only ways I came up with were either checking type() of each element of list, or using try and except, like so:
for i in list:
try: # i is a dict
print(i["foo"])
except: # i a list
for e in i:
print(e["foo"])
Is there any better way to do it?
You can use isinstance
Ex:
a = {"foo":1}
b = [{"foo":2}]
c = [{"foo":3}, {"foo":4}]
l = [a, b, c]
for i in l:
if isinstance(i, dict): #Check if dict object
print(i["foo"])
elif isinstance(i, list): #Check if list object
for j in i:
print(j["foo"])
Output:
1
2
3
4
You can check the datatype explicitly:
mylist = [a, b, c]
for i in mylist:
if isinstance(i,dict):
print(i["foo"])
elif isinstance(i,list):
for e in i:
print(e["foo"])
But this won't work if you call your variable list. This snippet illustrates why you should not do that.
If you want to do it for more nested elements like a list in a dict in a list you can create a function for every possible datatype.
class Printer():
def print_element(self, element):
if isinstance(element, dict):
self._print_dict(element)
elif isinstance(element, list):
self._print_list(element)
else:
print(element)
def _print_dict(self, element):
for key,value in element.items():
self.print_element(value)
def _print_list(self, element):
for value in element:
self.print_element(value)
a = {"foo":1}
b = [{"foo":2}]
c = [{"foo":3}, {"foo":4}, [1, {"foo":[9,8,7,6]}]]
Printer().print_element(c)
Output:
3
4
1
9
8
7
6
You can use a recursive generator with your try / except idea:
a = {"foo":1}
b = [{"foo":2}]
c = [{"foo":3}, {"foo":4}]
L = [a, b, c]
def get_values(x):
for i in x:
try:
yield i['foo']
except TypeError:
yield from get_values(i)
res = list(get_values(L)) # [1, 2, 3, 4]
Alternatively, using `isinstance:
def get_values(x):
for i in x:
if isinstance(i, dict):
yield i['foo']
else:
yield from get_values(i)
Note you should never name variables after built-ins, e.g. use list_ or L instead of list.
Related
I have a list seems like this :
a = ['jokowi','jokowidodo','ir h jokowidodo','teungku']
and a dictionary like this
{'jokowi': 'jokowi', 'jokowidodo': 'jokowi', 'ir h jokowidodo': 'jokowi'}
and make a mapping using this code:
list(map(data_dict.get,listakoh))
and then it returns:
['jokowi', 'jokowi', 'jokowi', None]
the question is how can I replace None in the result with the original value of my previous list, so None in the result must be 'teungku'
You can use a second argument to get as a default value:
list(map(lambda x: data_dict.get(x, x), a))
You can simply define your own function and map that.
a = ['jokowi','jokowidodo','ir h jokowidodo','teungku']
d = {'jokowi': 'jokowi', 'jokowidodo': 'jokowi', 'ir h jokowidodo': 'jokowi'}
def f(k):
global d
try:
return d[k]
except KeyError:
return k
r = list(map(f, a))
print(r)
['jokowi', 'jokowi', 'jokowi', 'teungku']
You can easily compare the mapped list with the original list and replace the None values with those from the actual list.
>>> new_list = list(map(data_dict.get,listakoh))
>>> for index, element in enumerate(new_list):
if element == None:
new_list[index]=a[index]
>>> print(new_list)
['jokowi', 'jokowi', 'jokowi', 'teungku']
I'm new in python,
I have a list like : A=['a','b','c']
and a list like B=[['a','c'],['a','c'],['b','b']]
i want to have a list like C=[2,1,2]
C stores occurrence of sublists that each element of A comes in B
that means 'a' is in 2 sublists
'b' is in 1 sublist
and 'c' is in 2 sublists,
how can I achieve this?
thanks
You can use sum:
a=['a','b','c']
b=[['a','c'],['a','c'],['b','b']]
final_list = [sum(i in c for c in b) for i in a]
Output:
[2, 1, 2]
You can loop over b and update a collections.Counter for each sublist, using set to remove duplicates:
from collections import Counter
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
counter = Counter()
for sublist in b:
counter.update(set(sublist))
c = [counter[x] for x in a]
# result: [2, 1, 2]
You can loop and compare in both lists
a=['a','b','c']
b=[['a','c'],['a','c'],['b','b']]
result = []
for letter in a:
count = 0
for l in b:
if letter in l:
count += 1
result.append(count)
You can try dict approach :
A=['a','b','c']
B=[['a','c'],['a','c'],['b','b']]
d={}
for i in A:
for j in B:
if i in j:
if i not in d:
d[i]=1
else:
d[i]+=1
print(d)
output:
{'c': 2, 'b': 1, 'a': 2}
You can use a list comprehension with sum to construct C.
C = [sum(elem in sub for sub in B) for elem in A]
This has the same effect as using nested for loops:
C = []
for elem in A:
sum = 0
for sub in B:
sum += elem in sub
C.append(sum)
Here is a solution with collections.defaultdict.
from collections import defaultdict
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
# initialise defaultdict
d = defaultdict(int)
# convert to sets for performance
a_set = set(a)
b_sets = list(map(set, b))
# loop through list of sets
for item in b_sets:
for i in item & a_set:
d[i] += 1
# retrieve counts in correct order
res = list(map(d.get, a))
print(res)
# [2, 1, 2]
Performance note
This may not matter, but the performance differential is interesting as it shows clearly the Counter overhead (4x slower).
from collections import defaultdict, Counter
a = ['a','b','c']
b = [['a','c'],['a','c'],['b','b']]
b = b*100000
def dd(a, b):
d = defaultdict(int)
a_set = set(a)
b_sets = list(map(set, b))
for item in b_sets:
for i in item & a_set:
d[i] += 1
return list(map(d.get, a))
def counter(a, b):
counter = Counter()
for sublist in b:
counter.update(set(sublist))
return [counter[x] for x in a]
assert dd(a, b) == counter(a, b)
%timeit dd(a, b) # 414 ms
%timeit counter(a, b) # 1.65 s
def lists(A: list) -> int:
'''Return the total number of lists in A (including A itself).
Each element of A and any nested lists are either ints or other lists.
Example:
>>> lists([1, 2, 3])
1
>>> lists([[1], [2], [3]])
4
>>> lists([[[1, 2], [], 3]])
4
'''
Does anyone know how to do this?
All I have is
for i in range(0, len(A)):
if (isinstance(A[i], list)):
count=count+1
return(lists(A[i]))
else:
B=A[i:]
return(count)
Here is a 'dirty' but easy way to do it
def lists(l):
'''
Return the total number of lists in A (including A itself).
Each element of A and any nested lists are either ints or other lists.
'''
# convert the list to string and count the ['s
# each [ is the start of a list, so the number of ['s equals
# the number of lists
nr_of_lists = str(l).count('[')
# return the number of sublists
return nr_of_lists
No recursion required
Here's one way to write it:
def numlists(lst, num = 1):
for item in lst:
if isinstance(item, list):
num += numlists(item)
return num
Sample outputs:
print(numlists([1, 2, 3])) # 1
print(numlists([[1], [2], [3]])) # 4
print(numlists([[[1, 2], [], 3]])) # 4
print(numlists([[1,[2,3,[4,5,[6]]]],7,8,[9]])) # 6
You should do this with recursion:
def count_list(a):
result = 0
if isinstance(a, list):
result += 1
try:
for b in a:
result += count_list(b)
except:
pass
return result
def lists(a):
if not isinstance(a, list):
return 0
s = 1
for x in a:
s += lists(x)
return s
print lists([])
print lists([1,2,3])
print lists([[1], [2], [3]])
print lists([[[1, 2], [], 3]])
def lists(A):
return 1 + sum(lists(e) if isinstance(e, list) else 0 for e in A)
I try to sum a list of nested elements
e.g, numbers=[1,3,5,6,[7,8]] should produce sum=30
I wrote the following code :
def nested_sum(L):
sum=0
for i in range(len(L)):
if (len(L[i])>1):
sum=sum+nested_sum(L[i])
else:
sum=sum+L[i]
return sum
The above code gives following error:
object of type 'int' has no len()
I also tried len([L[i]]), still not working.
Anyone can help? It is Python 3.3
You need to use isinstance to check whether an element is a list or not. Also, you might want to iterate over the actual list, to make things simpler.
def nested_sum(L):
total = 0 # don't use `sum` as a variable name
for i in L:
if isinstance(i, list): # checks if `i` is a list
total += nested_sum(i)
else:
total += i
return total
One alternative solution with list comprehension:
>>> sum( sum(x) if isinstance(x, list) else x for x in L )
30
Edit:
And for lists with more than two levels(thx #Volatility):
def nested_sum(L):
return sum( nested_sum(x) if isinstance(x, list) else x for x in L )
It is generally considered more pythonic to duck type, rather than explicit type checking. Something like this will take any iterable, not just lists:
def nested_sum(a) :
total = 0
for item in a :
try:
total += item
except TypeError:
total += nested_sum(item)
return total
I would sum the flattened list:
def flatten(L):
'''Flattens nested lists or tuples with non-string items'''
for item in L:
try:
for i in flatten(item):
yield i
except TypeError:
yield item
>>> sum(flatten([1,3,5,6,[7,8]]))
30
A quick recursion that uses a lambda to handle the nested lists:
rec = lambda x: sum(map(rec, x)) if isinstance(x, list) else x
rec, applied on a list, will return the sum (recursively), on a value, return the value.
result = rec(a)
This code also works.
def add_all(t):
total = 0
for i in t:
if type(i) == list: # check whether i is list or not
total = total + add_all(i)
else:
total += i
return total
An example using filter and map and recursion:
def islist(x):
return isinstance(x, list)
def notlist(x):
return not isinstance(x, list)
def nested_sum(seq):
return sum(filter(notlist, seq)) + map(nested_sum, filter(islist, seq))
And here is an example using reduce and recursion
from functools import reduce
def nested_sum(seq):
return reduce(lambda a,b: a+(nested_sum(b) if isinstance(b, list) else b), seq)
An example using plain old recursion:
def nested_sum(seq):
if isinstance(seq[0], list):
head = nested_sum(seq[0])
else:
head = seq[0]
return head + nested_sum(seq[1:])
An example using simulated recursion:
def nested_sum(seq):
stack = []
stack.append(seq)
result = 0
while stack:
item = stack.pop()
if isinstance(item, list):
for e in item:
stack.append(e)
else:
result += item
return result
Adjustment for handling self-referential lists is left as an exercise for the reader.
def sum_nest_lst(lst):
t=0
for l in lst:
if(type(l)==int):
t=t+l
if(type(l)==list):
t=t+sum(l)
print(t)
def nnl(nl): # non nested list function
nn = []
for x in nl:
if type(x) == type(5):
nn.append(x)
if type(x) == type([]):
n = nnl(x)
for y in n:
nn.append(y)
return sum(nn)
print(nnl([[9, 4, 5], [3, 8,[5]], 6])) # output:[9,4,5,3,8,5,6]
a = sum(nnl([[9, 4, 5], [3, 8,[5]], 6]))
print (a) # output: 40
A simple solution would be to use nested loops.
def nested_sum(t):
sum=0
for i in t:
if isinstance(i, list):
for j in i:
sum +=j
else:
sum += i
return sum
L = [1, 2, 3, [4, 5, 6], 5, [7, 8, 9]]
total = 0 # assign any var
for a in L: # assign index and start to iterate using if else
if (isinstance(a, list)): # since its a list you are basically repeating the prev step
for b in a:
total += b
else:
total += a
print(total)
def list_sum(L):
return sum(list_sum(x) if isinstance(x, list) else x for x in L)
def nested_sum(lists):
total = 0
for lst in lists:
s = sum(lst)
total += s
return total
#nested sum
l = [[1, 2], [3,5], [6,2], [4, 5, 6,9]]
def nested_sum(lst):
sum = 0
for i in lst:
for j in i:
sum = sum + j
print(sum)
nested_sum(l)
I have a few arrays containing integer and strings. For example:
myarray1 = [1,2,3,"ab","cd",4]
myarray2 = [1,"a",2,3,"bc","cd","e",4]
I'm trying to combine only the strings in an array that are next to each other. So I want the result to be:
newarray1= [1,2,3,"abcd",4]
newarray2= [1,"a",2,3,"bccde",4]
Does anyone know how to do this? Thank you!
The groupby breaks the list up into runs of strings and runs of integers. The ternary operation joins the groups of strings and puts them into a temporary sequence. The chain re-joins the strings and the runs of integers.
from itertools import groupby, chain
def joinstrings(iterable):
return list(chain.from_iterable(
(''.join(group),) if key else group
for key, group in
groupby(iterable, key=lambda elem: isinstance(elem, basestring))))
>>> myarray1 = [1,2,3,"ab","cd",4]
>>> newarray1 = [myarray1[0]]
>>> for item in myarray1[1:]:
... if isinstance(item, str) and isinstance(newarray1[-1], str):
... newarray1[-1] = newarray1[-1] + item
... else:
... newarray1.append(item)
>>> newarray1
[1, 2, 3, 'abcd', 4]
reduce(lambda x, (tp, it): tp and x + ["".join(it)] or x+list(it), itertools.groupby( myarray1, lambda x: isinstance(x, basestring) ), [])
a = [1,2,3,"ab","cd",4]
b = [1,a,2,3,"bc","cd","e",4]
def func(a):
ret = []
s = ""
for x in a:
if isinstance(x, basestring):
s = s + x
else:
if s:
ret.append(s)
s = ""
ret.append(x)
return ret
print func(a)
print func(b)