How to add the list elements in python [duplicate] - python

This question already has answers here:
sum of nested list in Python
(14 answers)
Closed 8 years ago.
for example I have a list with numbers like this:
a = [10,[20,30],40]
or
b = [[10,20],30]
Now I have to add all the elements in the above lists.
so that if add the first list then I should get the answer as follows: 10+20+30+40 = 100.
and for the second one b as follows: 10+20+30 = 60.
The solution is to be expressed as a function.
I have tried this one but it can be used for only adding if there is no nested list.
def sum(t):
total = 0
for x in t:
total = total+x
return total
Now can anyone help me solve this kind of problem in python programming.
Thank you in advance!!!!!

You can use reduce:
x = reduce(lambda prev,el: prev+([x for x in el] if type(el) is list else [el]), x, [])
And use its result to feed your loop.
def sum(t):
t = reduce(lambda prev,el: prev+([x for x in el] if type(el) is list else [el]), t, [])
total = 0
for x in t:
total = total+x
return total

You can recursively flatten into a single list:
def flatten(lst, out=None):
if out is None:
out = []
for item in lst:
if isinstance(item, list):
flatten(item, out)
else:
out.append(item)
return out
Now you can just use sum:
>>> sum(flatten([10, [20, 30], 40]))
100

You need to define a recursion 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)

Seems like the best approach would be to iterate over the top-level list and check each element's type (using is_instance(type, item)). If it's an integer, add it to the total, otherwise if it's a list, iterate over that list.
Making your function recursive would make it most usable.
Edit: For anybody stumbling upon this question, here's an example.
def nested_sum(input_list):
total = 0
for element in input_list:
if isinstance(element, int):
total += element
elif isinstance(element, list):
total += nested_sum(element)
else:
raise TypeError
return total
Usage:
my_list = [72, 5, [108, 99, [8, 5], 23], 44]
print nested_sum(my_list)
>>> 364

Related

How can I count the depth in a list of lists?

I want to count the depth in a list of lists, so not the amount of elements but the maximum depth one list can have.
This is my function:
def max_level(lst):
print(max_level([1, [[[2, 3]]], [[3]]])))
should return 4
You can try:
def max_level(lst):
return isinstance(lst, list) and max(map(max_level, lst)) + 1
print(max_level([1, [[[2, 3]]], [[3]]]))
Output:
4
Explanation:
First check if object passed into the recursive function is of type list:
def max_level(lst):
return isinstance(lst, list)
If so, proceed to add up the Trues in the list:
and max(map(max_level, lst)) + 1
where the max(map(max_level, lst)) returns the current amount of Trues, and the + 1 is to add one more.
If there can be empty lists, you can replace lst with lst or [0], where the or will tell python to use the list on the left side of it if its not empty, else use the [0]:
def max_level(lst):
return isinstance(lst, list) and max(map(max_level, lst or [0])) + 1
print(max_level([1, [], [[]]]))
Output:
3
Addressing #cdlane's comment, if you don't want to mix boolean values with integer values, you can add an int() wrapper to the isinstance() call:
def max_level(lst):
return int(isinstance(lst, list)) and max(map(max_level, lst or [0])) + 1
I want to search through a list that is empty as well
Give this a try:
def max_level(thing):
return 1 + (max(map(max_level, thing)) if thing else 0) if isinstance(thing, list) else 0
I've reworked #AnnZen's initial solution to add an extra check for empty lists and also to not mix booleans and integers.

How to remove a type string element from a list in python?

So basically, I have to write a code that returns the max value of an object in a list. If the list has a string, the code has to remove the string, then return the max value from the list.
This is the code that I've tried so far:
for i in lst:
if i != int:
if i != float:
filtered_lst = filter(lambda i: not (type(i) is str), lst)
if filtered_lst == []:
print(' ')
else:
return max(filtered_lst)
else:
return max(lst)
else:
return max(lst)
Which worked for the most part, however if an input is all strings (such as max_args(['5','2']), it returns an error, particularly 'max() contains an empty argument'. Any tips on how to fix this? Thanks!
I think you're making this problem more complicated than it has to be, you can just check for the case of an empty list and print whatever you want accordingly
lst = [1,2,3,"hello", 3, "world"]
fil_lst = [i for i in lst if not type(i) is str]
if len(fil_lst) == 0:
print("Could not find max")
else:
print(max(fil_lst))
how about the below? jsut remove the strings and find the max int
lst = ['99', 12, '1045', 18, 55]
lst1 = [x for x in lst if isinstance(x, int)]
print(lst1)
if lst1:
print(max(lst1))

Length of 2d list in python

I have a 2D list, for example mylist =[[1,2,3],[4,5,6],[7,8,9]].
Is there any way I can use len() function such that I can calculate the lengths of array indices? For example:
len(mylist[0:3])
len(mylist[1:3])
len(mylist[0:1])
Should give:
9
6
3
length = sum([len(arr) for arr in mylist])
sum([len(arr) for arr in mylist[0:3]]) = 9
sum([len(arr) for arr in mylist[1:3]]) = 6
sum([len(arr) for arr in mylist[2:3]]) = 3
Sum the length of each list in mylist to get the length of all elements.
This will only work correctly if the list is 2D. If some elements of mylist are not lists, who knows what will happen...
Additionally, you could bind this to a function:
len2 = lambda l: sum([len(x) for x in l])
len2(mylist[0:3]) = 9
len2(mylist[1:3]) = 6
len2(mylist[2:3]) = 3
You can flatten the list, then call len on it:
>>> mylist=[[1,2,3],[4,5,6],[7,8,9]]
>>> import collections
>>> def flatten(l):
... for el in l:
... if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
... for sub in flatten(el):
... yield sub
... else:
... yield el
...
>>> len(list(flatten(mylist)))
9
>>> len(list(flatten(mylist[1:3])))
6
>>> len(list(flatten(mylist[0:1])))
3
You can use reduce to calculate the length of array indices like this, this can also handle the scenario when you pass in something like mylist[0:0]:
def myLen(myList):
return reduce(lambda x, y:x+y, [len(x) for x in myList], 0)
myLen(mylist[0:3]) = 9
myLen(mylist[1:3]) = 6
myLen(mylist[0:1]) = 3
myLen(mylist[0:0]) = 0
I like #Haidro's answer, which works for arbitrary nesting, but I dislike the creation of the intermediate list. Here's a variant that avoids that.
try:
reduce
except NameError:
# python3 - reduce is in functools, there is no basestring
from functools import reduce
basestring = str
import operator
import collections
def rlen(item):
"""
rlen - recursive len(), where the "length" of a non-iterable
is just 1, but the length of anything else is the sum of the
lengths of its sub-items.
"""
if isinstance(item, collections.Iterable):
# A basestring is an Iterable that contains basestrings,
# i.e., it's endlessly recursive unless we short circuit
# here.
if isinstance(item, basestring):
return len(item)
return reduce(operator.add, (rlen(x) for x in item), 0)
return 1
For the heck of it I've included a generator-driven, fully-recursive flatten as well. Note that this time there's a harder decision to make about strings (the short circuit above is trivially correct since as len(some_string) == sum(len(char) for char in some_string)).
def flatten(item, keep_strings=False):
"""
Recursively flatten an iterable into a series of items. If given
an already flat item, just returns it.
"""
if isinstance(item, collections.Iterable):
# We may want to flatten strings too, but when they're
# length 1 we have to terminate recursion no matter what.
if isinstance(item, basestring) and (len(item) == 1 or keep_strings):
yield item
else:
for elem in item:
for sub in flatten(elem, keep_strings):
yield sub
else:
yield item
If you don't need arbitrary nesting—if you're always sure that this is just a list of lists (or list of tuples, tuple of lists, etc)—the "best" method is probably the simple "sum of generator" variant of #Matt Bryant's answer:
len2 = lambda lst: sum(len(x) for x in lst)
how about len(ast.flatten(lst))? only works in py2k afaik
It's
from compiler import ast
len(ast.flatten(lst))
since
ast.flatten([1,2,3]) == [1,2,3]
ast.flatten(mylist[0:2]) == [1,2,3,4,5,6]
ast.flatten(mylist) == [1,2,3,4,5,6,7,8,9]

Find monotonic sequences in a list?

I'm new in Python but basically I want to create sub-groups of element from the list with a double loop, therefore I gonna compare the first element with the next to figure out if I can create these sublist, otherwise I will break the loop inside and I want continue with the last element but in the main loop:
Example: 5,7,8,4,11
Compare 5 with 7, is minor? yes so include in the newlist and with the inside for continue with the next 8, is minor than 5? yes, so include in newlist, but when compare with 4, I break the loop so I want continue in m with these 4 to start with the next, in this case with 11...
for m in xrange(len(path)):
for i in xrange(m+1,len(path)):
if (path[i] > path[m]):
newlist.append(path[i])
else:
break
m=m+i
Thanks for suggestions or other ideas to achieve it!
P.S.
Some input will be:
input: [45,78,120,47,58,50,32,34]
output: [45,78,120],[47,58],50,[32,34]
The idea why i want make a double loops due to to compare sub groups of the full list,in other way is while 45 is minor than the next one just add in the new list, if not take the next to compare in this case will be 47 and start to compare with 58.
No loop!
Well at least, no explicit looping...
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use a dictionary here to work around closure limitations
state = { 'prev': lst[0], 'n': 0 }
def grouper(x):
if x < state['prev']:
state['n'] += 1
state['prev'] = x
return state['n']
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
Usage (work both with Python 2 & Python 3):
>>> data = [45,78,120,47,58,50,32,34]
>>> print (list(process(data)))
[[45, 78, 120], [47, 58], [50], [32, 34]]
Joke apart, if you need to group items in a list itertools.groupby deserves a little bit of attention. Not always the easiest/best answer -- but worth to make a try...
EDIT: If you don't like closures -- and prefer using an object to hold the state, here is an alternative:
class process:
def __call__(self, lst):
if len(lst) < 1:
return lst
self.prev = lst[0]
self.n = 0
return [ list(g) for k, g in itertools.groupby(lst, self._grouper) ]
def _grouper(self, x):
if x < self.prev:
self.n += 1
self.prev = x
return self.n
data = [45,78,120,47,58,50,32,34]
print (list(process()(data)))
EDIT2: Since I prefer closures ... but #torek don't like the dictionary syntax, here a third variation around the same solution:
import itertools
def process(lst):
# Guard clause against empty lists
if len(lst) < 1:
return lst
# use an object here to work around closure limitations
state = type('State', (object,), dict(prev=lst[0], n=0))
def grouper(x):
if x < state.prev:
state.n += 1
state.prev = x
return state.n
return [ list(g) for k, g in itertools.groupby(lst, grouper) ]
data = [45,78,120,47,58,50,32,34]
print (list(process(data)))
I used a double loop as well, but put the inner loop in a function:
#!/usr/bin/env python
def process(lst):
def prefix(lst):
pre = []
while lst and (not pre or pre[-1] <= lst[0]):
pre.append(lst[0])
lst = lst[1:]
return pre, lst
res=[]
while lst:
subres, lst = prefix(lst)
res.append(subres)
return res
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], [50], [32, 34]]
The prefix function basically splits a list into 2; the first part is composed of the first ascending numbers, the second is the rest that still needs to be processed (or the empty list, if we are done).
The main function then simply assembles the first parts in a result lists, and hands the rest back to the inner function.
I'm not sure about the single value 50; in your example it's not in a sublist, but in mine it is. If it is a requirement, then change
res.append(subres)
to
res.append(subres[0] if len(subres)==1 else subres)
print process([45,78,120,47,58,50,32,34])
=> [[45, 78, 120], [47, 58], 50, [32, 34]]
#uselpa's version is fine. Here's mine (same issue with [50] instead of just 50) that uses collections.deque to be a little more efficient, and also some long comments...
#! /usr/bin/env python
from collections import deque
def process(lst):
"""
Given a list of values that is not sorted (such that for some
valid indices i,j, i<j, sometimes lst[i] > lst[j]), produce a
new list-of-lists, such that in the new list, each sublist *is*
sorted:
for all sublist \elem returnval:
assert_is_sorted(sublist)
and furthermore this is the minimal set of sublists required
to achieve the condition.
Thus, if the input list lst is actually sorted, this returns
[list(lst)].
"""
def sublist(deq):
"""
Pop items off the front of deque deq until the next one
goes backwards. Return the constructed sub-list.
"""
sub = [deq.popleft()]
while deq and deq[0] >= sub[-1]:
sub.append(deq.popleft())
return sub
# Make a copy of lst before modifying it; use a deque so that
# we can pull entries off it cheaply.
deq = deque(lst)
output = []
ret = []
while deq:
ret.append(sublist(deq))
return ret
print process([45,78,120,47,58,50,32,34])
(Incidentally, in the days before collections.deque I'd probably just use a reversed copy of lst and use lst.pop() in sublist. That's not quite as obvious, though.)
why not simply use a single for loop instead of using itertool and all fancy stuff.
def list_test(inlist, outlist):
if not inlist:
return []
prev=inlist[0]
x=[]
for item in inlist:
if item >= prev:
x.append(item)
else:
outlist.append(x)
x=[]
x.append(item)
prev=item
if x:
outlist.append(x)
in_list=[1,0,1,2,3]
out_list = []
list_test(in_list, out_list)
print(out_list)
O/p:[[1], [0, 1, 2, 3]]

Flattening a list recursively [duplicate]

This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 6 months ago.
I am trying to flatten lists recursively in Python. I have this code:
def flatten(test_list):
#define base case to exit recursive method
if len(test_list) == 0:
return []
elif isinstance(test_list,list) and type(test_list[0]) in [int,str]:
return [test_list[0]] + flatten(test_list[1:])
elif isinstance(test_list,list) and isinstance(test_list[0],list):
return test_list[0] + flatten(test_list[1:])
else:
return flatten(test_list[1:])
I am looking for a very basic method to recursively flatten a list of varying depth that does not use any for loops either.
My code does not pass these tests:
flatten([[[[]]], [], [[]], [[], []]]) # empty multidimensional list
flatten([[1], [2, 3], [4, [5, [6, [7, [8]]]]]]) # multiple nested list
What is wrong with the code, and how can I fix it?
This handles both of your cases, and I think will solve the general case, without any for loops:
def flatten(S):
if S == []:
return S
if isinstance(S[0], list):
return flatten(S[0]) + flatten(S[1:])
return S[:1] + flatten(S[1:])
li=[[1,[[2]],[[[3]]]],[['4'],{5:5}]]
flatten=lambda l: sum(map(flatten,l),[]) if isinstance(l,list) else [l]
print flatten(li)
Here's a possible solution without any loops or list comprehensions, just using recursion:
def flatten(test_list):
if isinstance(test_list, list):
if len(test_list) == 0:
return []
first, rest = test_list[0], test_list[1:]
return flatten(first) + flatten(rest)
else:
return [test_list]
Well, if you want it a lisp way, let's have it.
atom = lambda x: not isinstance(x, list)
nil = lambda x: not x
car = lambda x: x[0]
cdr = lambda x: x[1:]
cons = lambda x, y: x + y
flatten = lambda x: [x] if atom(x) else x if nil(x) else cons(*map(flatten, [car(x), cdr(x)]))

Categories