Give a method that sums all the numbers in a list. The method should be able to skip elements that are not numbers. So, sum([1, 2, 3]) should be 6 but sum(['A', 1, 'B', 2, 3]) should also be 6. How can I accomplish this?
What I have already tried so far:
def foo(list):
dict = "ABCDEFGHIJKLMN"
n = 0
for i in range(0, len(list) - 1):
if list[i].str in dict:
""
else:
n= n + list[i]
return n
print foo([1, 2, 3, 4, 5, 6, "A", "B"])
You can do this with a simple one liner:
l1 = [1, 2, 3, 'A']
sum(filter(lambda i: isinstance(i, int), l1))
# prints 6
Or, if you need it inside a function:
def foo(l1):
return sum(filter(lambda i: isinstance(i, int), l1))
Additionally, as noted in the comments, don't use names like dict and list for your variables; *they will shadow they build-in names for the dictionary (dict) and (list) types. You'll then need to explicitly del dict, list in order to use them as intended.
But, let me explain. What filter does is here is:
a) It takes a function as its first argument:
# this function will return True if i is an int
# and false otherwise
lambda i: isinstance(i, int)
and then takes every element inside the list l1 (second argument) and evaluates whether it is True or False based on the function.
b) Then, filter will essentially filter out any objects inside list l1 that are not instances of int (i.e the function returns False for them). As a result, for a list like [1, 2, 3, 'A'] filter is going to return [1, 2, 3] which will then be summed up by sum().
Some Examples:
foo([1, 2, 3, 'A'])
# 6
foo([1, 2, 3])
# 6
foo([1, 2, 3, 'HELLO', 'WORLD'])
# 6
Slight caveat:
As is, this doesn't sum up float values, it drops them (and any other numeric types for that case). If you need that too, simply add the float type in the lambda function as so:
lambda i: isinstance(i, (int, float))
Now, your function sums floats too:
foo([1, 2, 3, 3.1, 'HELLO', 'WORLD'])
# 9.1
Add any other types as necessary in the lambda function to catch the cases that you need.
A catch all case:
As noted by #Copperfield you can check for objects that are instances of any number by utilizing the numbers.Number abstract base class in the numbers module. This acts as a catch-all case for numeric values:
import numbers # must import
sum(filter(lambda i: isinstance(i, numbers.Number), l1))
Simpler and a bit faster, too:
Additionally, as noted by #ShadowRanger, and since lambda might not be the most comfortable construct for new users, one could simply use a generator expression (which is also faster) with sum to get the same exact result:
sum(val for val in l1 if isinstance(val, numbers.Number))
The Pythonic way is to do a try/except. While you could do this in a one liner, I prefer to break things out a bit to see exactly what is happening.
val=0
for item in list:
try:
val+=int(item)
except ValueError:
pass
If you want to include floating points, simply change the int to a float. Floating points are anything with a decimal, among others.
sum([x for x in list if isinstance(x, (int, long, float))])
use filter and isinstance like this
>>> test = [1,2,3,4,5,6,"A","B"]
>>> sum(filter(lambda x:isinstance(x,int),test))
21
>>>
def foo(list):
dict= "ABCDEFGHIJKLMN"
n=0
for i in range(0,len(list)-1):
if str(list[i]) in dict:
""
else:
n= n+list[i]
return n
print foo([1,2,3,4,5,6,"A","B"])
def filtersum(L):
if not L: return 0
if not isinstance(L[0], int): return filtersum(L[1:])
return L[0] + filtersum(L[1:])
Output:
In [28]: filtersum([1,2,3])
Out[28]: 6
In [29]: filtersum([1,'A', 2,3])
Out[29]: 6
def sum_intable(object_list):
return sum(val for val in object_list
if isinstance(val, (int, float)))
Related
I'm doing exercises, and I have a problem in one of them.
I have a print the smallest, and the highest number in a list. When the program sees a string, it has to ignore it. I don't know how to do it.
def find_hi_lo(list):
return(min(list), max(list))
a = find_hi_lo([10, 2, 3, 4, 6])
print(a)
(2, 10)
a = find_hi_lo([10, 2, 3, 'aaa', 4, 6])
print(a)
Gives the error:
TypeError: unorderable types: str() < int()
Can you help me?
You can filter out all the undesired elements first.
from numbers import Number
def find_hi_lo(list0):
temp = list(filter(lambda x: isinstance(x, Number), list0))
return(min(temp), max(temp))
You can use a list comprehension to filter out the non-numeric values
def find_hi_lo(data):
data = [i for i in data if isinstance(i, float) or isinstance(i, int)]
return min(data), max(data)
>>> find_hi_lo([10, 2, 3, 'aaa', 4, 6])
(2, 10)
Lists can contain values of arbitrary types, but they work best when you restrict them to values of the same type (or, at least, values supporting any protocol expected by the consumer). In this case, both min and max expect values that are comparable to each other. The easiest thing to do here is to filter the strings out before you pass the list to find_hi_lo. Ideally, you would do this by not adding strings to the list in the first place, but you can remove them on demand like so:
find_hi_lo([x for x in [10, 2, 3, 'aaa', 4, 6] if not isinstance(x, str)])
Being new to python I am just trying to figure out the difference between filter() and map().
I wrote a sample script as follows:
def f(x): return x % 2 == 0
def m(y): return y * 2
list = [1,2,3,4]
flist = filter(f, list)
print(list)
print(flist)
mlist = map(m, list)
print(list)
print(mlist)
We see that to both the filter and map we pass a list and assign their output to a new list.
Output of this script is
[1, 2, 3, 4]
[2, 4]
[1, 2, 3, 4]
[2, 4, 6, 8]
Question arises is that function call of both filter and map looks same so how will they behave if we interchange the contents of functions passed to them.
def f(x): return x * 2
def m(y): return y % 2 == 0
list = [1,2,3,4]
flist = filter(f, list)
print(list)
print(flist)
mlist = map(m, list)
print(list)
print(mlist)
This results in
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[False, True, False, True]
This shows filter evaluates the function and if true it returns back the passed element.
Here the function
def f(x): return x * 2
evaluates to
def f(x): return x * 2 != 0
In contrast map evaluates the function expression and returns back the result as items.
So filter always expects its function to do comparison type of task to filter out the elements while map expects its functions to evaluate a statement to get some result.
Is this understanding correct?
They both work a little bit differently but you've got the right idea.
Map takes all objects in a list and allows you to apply a function to it
Filter takes all objects in a list and runs that through a function to create a new list with all objects that return True in that function.
Here's an example
def square(num):
return num * num
nums = [1, 2, 3, 4, 5]
mapped = map(square, nums)
print(*nums)
print(*mapped)
The output of this is
1 2 3 4 5
1 4 9 16 25
Here's an example of filter
def is_even(num):
return num % 2 == 0
nums = [2, 4, 6, 7, 8]
filtered = filter(is_even, nums)
print(*nums)
print(*filtered)
The output of this would be
2 4 6 7 8
2 4 6 8
In map: Function will be applied to all objects of iterable.
In filter: Function will be applied to only those objects of iterable who goes True on the condition specified in expression.
As per my understanding below are the difference between map and filter:
def even(num):
if(num % 2 == 0):
return 'Even'
num_list = [1,2,3,4,5]
print(list(filter(even,num_list))) ->>>>>>>output: [2, 4]
print(list(map(even,num_list))) ->>>>>>> output: [None, 'Even', None, 'Even', None]
So, we can say that:
filter(): formats new list that contains elements which satisfy specific condition.
map(): function iterates through a all items in the given iterable and executes a function which we passed as an argument.
I think yes you got the picture pretty much.
both Map and filter are ways of applying function to iterables.
in Map you can use multiple iterables
definition : map(function_object, iterable1, iterable2,...)
whereas
in filter only one iterable can be used
definition : filter(function_object, iterable)
further in filter the function_object has to return boolean only.
for sake of example following is the Map with multiple iterables as input
list_a = [1, 2, 3]
list_b = [10, 20, 30]
map(lambda x, y: x + y, list_a, list_b) # Output: [11, 22, 33]
The filter() and map() functions are a little bit different.
While Maps takes a normal function, Filter takes Boolean functions. As a matter of fact, filter are maps with conditional logic, a Boolean logic.
Your example is too accurate.
In filter function your supposed to pass a function and a list(the function must evaluate to true or false). If the element passed in the function returns true the filter function will put the element passed into a new list. Where as map function will take an element pass it through a function and return the output of the function and store that to the new list.
map(): Function will be applied to all objects of iterable, we can use as many literables as wee needed
filter(): Function will be applied to only those objects of iterable and added to result which item is True, we can use only one literable
In the below, code 0 is not add in the filter function because 0 is a representation for False in some cases so it is not added to the filter and added in the map function result
def check(num):
return num*1
nums = [0,2, 4, 6, 7, 8]
result = filter(check, nums)
print(list(result))
def check(num):
return num*1
nums = [0,2, 4, 6, 7, 8]
result = map(check, nums)
print(list(result))
map() applies any applicable logic presented to any number of arguments of type list and returns an iterable containing values mapped to each respective members of the argument list(s).
example:
m = map(lambda x,y: 10+x+y, [1,2,3,4],[10,20,30,40])
print(list(m))
output:
[21, 32, 43, 54]
filter() applies the condition specified to one argument of type list and returns an iterable containing values that satisfy the specified condition and thus selected from the argument.
example:
f = filter(lambda x: x<3, [1,2,3,4])
print(list(f))
output:
[1, 2]
The main difference between a map and a filter is the return of values. A map will always have a representation for elements in the list. The filter will filter out the only elements that will meet the conditions in the function.
def checkElementIn(a):
nameList = ['b','a','l','l']
if a in nameList:
return a
testList = ['r','e','d','b','a','l','l']
m_list = map(checkElementIn,testList)
for i in m_list:
print(i)
None
None
None
b
a
l
l
f_list = filter(checkElementIn,testList)
for i in f_list:
print(i)
b
a
l
l
Those are completely different
just take a look at this clear example down below:
def sqr(x):
return x%2==0
mp = map(sqr, [-1,0,1,2,3,4,5,6])
print(list(mp))
[False, True, False, True, False, True, False, True]
fl = filter(sqr, [-1,0,1,2,3,4,5,6])
print(list(fl))
[0, 2, 4, 6]
as you can see in this clear example the filter doesn't care about the function results! It just checks which one of the list items would be true belonging to the calculation def, and the return is a list [0, 2, 4, 6] which means we have got a true result of numbers
I am trying to sort a list of numbers depending on whether it is odd or even (even gains higher priority).
Example:
a=[1,2,3,4]
a.sort(key=org(a)) sorted will produce [2,4,1,3]. I want to use the sort method
def org(a):
for i in range(len(a)):
if a[i]%2==0:
b.append(a[i])
b.sort()
else:
c.append(a[i])
c.sort()
print(b+c)
I got this error from running a.sort(key=org(a))
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
a.sort(key=org(a))
TypeError: 'list' object is not callable
I realize that sorting it every time makes it slow. Which other way can I do this without having to sort after every loop?
To sort by "evenness" and then by magnitude, you can use a function that returns a tuple
>>> a=[1,2,3,4]
>>> a.sort(key=lambda x: (x % 2, x))
>>> a
[2, 4, 1, 3]
To sort the odd entries first, you can simply negate the value of the modulus. This is a useful trick for reversing the sort of numeric fields in general.
>>> a.sort(key=lambda x:(-(x % 2), x))
>>> a
[1, 3, 2, 4]
It looks like you were on the right track:
a = [1,2,3,4]
>>> sorted(a,key=lambda x: x%2)
[2, 4, 1, 3]
Here sorted is a function that returns a sorted list. You can also use the sort method, as John said. Apparently if your original list is not sorted, sorted will not work, so you then you would have to do:
a = [3,2,1,4]
a.sort()
newList = sorted(a,key=lambda x: x%2)
at which point John's code is probably cleaner. His can also be implemented with the sorted function though, by doing sorted(a,key=lambda x: (x%2,x)).
one can use helper function from intertools
def partition_by_pred(pred, iterable):
from itertools import tee, filterfalse
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
l, r = partition_by_pred(lambda x: False if x % 2 == 0 else True ,[1,2,3,4] )
print(*l,*r)
2 4 1 3
I have a bug in my attempt to add to a list a sequence of numbers recursively. E.g. if the input is [5,3,9], I do [5+1,3+2,9+3] and output [6,5,12]. I want to do this recursively so the way I'm doing it is going through and adding one to a smaller and smaller part of the list as below:
def add_position_recur(lst, number_from=0):
length = len(lst)
# base case
if (length <= 1):
lst = [x+1 for x in lst]
print "last is", lst
else:
lst = [x+1 for x in lst]
print "current list is", lst
add_position_recur(lst[1:], number_from)
return lst
The problem, though, is that all this does is add 1 to every element of the list. Where is the bug? Is it to do with the way I return the list in the base case?
When you recurse down your call stack you slice lst which creates a new list, this is not the same as what you return, so you will only ever return the changes you've applied to your list in the first call to the function, losing all changes further down the stack:
>>> add_position_recur([1,2,3])
[2, 3, 4]
This should have returned [2, 4, 6].
You need to consider reassembling the list on the way out to get the changes.
return [lst[0]] + add_position_recur(lst[1:], number_from)
and you need to return lst in your base case:
def add_position_recur(lst, number_from=0):
length = len(lst)
# base case
if (length <= 1):
lst = [x+1 for x in lst]
return lst
else:
lst = [x+1 for x in lst]
return [lst[0]] + add_position_recur(lst[1:], number_from)
>>> add_position_recur([1,2,3])
[2, 4, 6]
However, this is quite a complicated approach to this recursion. It is idiomatic for the base case to be the empty list, otherwise take the head and recurse down the tail. So something to consider which uses the number_from:
def add_position_recur(lst, number_from=1):
if not lst:
return lst
return [lst[0]+number_from] + add_position_recur(lst[1:], number_from+1)
>>> add_position_recur([1,2,3])
[2, 4, 6]
This also has the advantage(?) of not changing the passed in lst
Why don't you instead do something like this:
def func(lon, after=[]):
if not l:
pass
else:
v = len(lon) + lon[-1]
after.append(v)
func(lon[:-1], after)
return after[::-1]
The output of the function for the example you provided matches what you want.
Currently, you are simply adding 1 to each value of your list.
lst = [x+1 for x in lst]
Rather, you should be increasing a variable which is being added to x with each iteration of x in lst.
lst = [x+(lst.index(x)+1) for x in lst]
This solution assumes that you want the number being added to x to depend on its position in the list relative to the start of the list, rather than being dependent on the position of x relative to the first element which was >1. Meaning, do you want to add 1 or 3 to the value 2 in the following list? The solution above adds three.
lst = [0.5, 0.1, 2, 3]
I am trying to raise a TypeError if a list contains an element of string data type when a mixed type of list given. I was able to do this with the code below but I wonder if there is a better way to achieve the same result.
numbers = [1, "two", 3, 4, 5]
myStrList = [x for x in numbers if isinstance(x, str)]
if len(myStrList) != 0:
raise TypeError
else:
#do something
You can use any and a generator expression:
numbers = [1, "two", 3, 4, 5]
if any(isinstance(x, str) for x in numbers):
raise TypeError
else:
#do something
Aside from the fact that there is less code, this solution is actually a lot more efficient than your current one. This is because, instead of building an unnecessary list, it will lazily compute the result and only check as many items as are necessary.
Also, if you are using Python 2.x, then it might be better to test for instances of basestring rather than just str. This will allow you to also catch any unicode strings that are inside the list.
Filtering the list for strings works too:
L=[0, 0, 1, 2, 'a', 3, 0, 0, 'l']
if filter(lambda item: isinstance(item, str), L) != []:
raise TypeError
else:
#do something
If the filtered list is empty, no strings are in the original list.