Suppose a = [[1,2,3],[1,2,3]]
reduce(lambda x,y: x==y, a) returns True
But if a = [[1,2,3],[1,2,3],[1,2,3]]
reduce(lambda x,y: x==y, a) returns False
Why in the second case, the outcome is False?
please help
thanks
Try this instead, it works for lists of any size:
all(e == a[0] for e in a)
Notice that your proposed solution using reduce doesn't work for more than two items, as the accumulated value after the first comparison is True, and you'd be comparing True against each of the elements from that point on, and obviously that's not going to work.
You are not reducing the lists. The return value of your lambda is True or False, which is then used as input parameters to further calls to the same lambda function. So you end up comparing a boolean with a list. Therefore, the reducing function should return the same type as it input parameters.
You were probably looking for what other answers proposed instead: use all().
You can still use reduce! Check out this magic:
bool(reduce(lambda x,y: (x==y)*x, a))
Since the return value of the lambda for x==y is True or False, that can be multiplied by the input and then used in the next comparison because True*[1,2,3] is [1,2,3]. It also works for strings, True*"MyString" is "MyString".
Try it. However, this method will not work for a list of zeros.
Because first time reduce compare [1,2,3] == [1, 2, 3] and it's true
next time it compare True and [1,2,3] and it's false.
help(reduce)
Help on built-in function reduce in module __builtin__:
reduce(...)
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5).
a = [range(1, 4), range(1, 4), range(1, 4)]
To evaluate reduce(operator.eq, a) the reduce function will first evaluate the function operator.eq on the first two elements of a to obtain True. Then it will call operator.eq again with True and range(1, 4) as the two arguments, and obtain False which is the final result of reduce.
Perhaps you are wanting:
from functools import partial
import operator
allequal = reduce(partial(operator.eq, a[0]), a[1:])
Why in the second case, the outcome is False
Because reduce(lambda x, y: x == y, (a, b, c, d)) does not mean (a == b) and (b == c) and (c == d); it means (((a == b) == c) == d). a == b will produce either True or False, which then gets compared to c.
Related
I have a tuple like (p1, p2) (for example (5,3) or (2,1))
I want to apply the same operation to each element of the tuple. (Incidentally this operation will give for each element another tuple, so I will have a tuple of tuples but this is not a necessary condition)
First I thought something like
for element in (3,2):
res=function(element)
but first, this doesn't seem a elegant solution and two, I would still have to form a tuple from each res to get a (function(3),function(2)) solution
How can I apply a function (with several arguments) to each element of the tuple once and get a tuple of returned values?
If I understand you question correctly, map should to the job as well:
tuple(map(func, tpl))
where func is a one-argument function you defined.
Now, if you have a function with several arguments you would like to apply to each element, like:
def func(x, y, z): return x*y+z
I assume that 2 elements (let's take y and z) are fixed, while x will be determined by the value in the tuple.
There are two approaches in my view:
Either you define a new function with 2 fixed arguments and map:
def func1(x): return func(x, 3, 2)
tuple(map(func1, tpl))
Or map as follows (I think it is less elegant, but it is a matter of tastes, maybe):
tuple(map(lambda x: func(x, 3, 2), tpl))
One approach uses a list comprehension:
def add_one(x):
return x + 1
tpl = (5, 3)
output = tuple([add_one(x) for x in tpl])
print(output) # (6, 4)
You may consider using the generator comprehension then convert it to tuple:
>>> data = (3, 5, 7, 9)
>>> tuple((function(x) for x in data))
I have the following snippet of code to find out whether any pair from a given list of numbers matches a given sum.
I have implemented the function as follows
def google(numbers, total):
complement =[]
for x in numbers:
if x in complement:
return True
else: complement.append(total-x)
return False
print google([1,2,3,4,5],8)
My question is, is there ANY POSSIBLE way of implementing this as a generator expression. ?
For example is there a way to check if the currently partially created generator has a given value inside comprehension ?
If you really want to do this, all things are possible, but not all things are desirable:
from itertools import combinations, dropwhile
def google(numbers, total):
return bool(next(dropwhile(lambda c: sum(c) != total, combinations(numbers, 2)), False))
We iterate through all the possible 2-number combinations of numbers using combinations and compare them to total.
Using dropwhile, we can emulate the short-circuit behaviour of your original code, getting only the first combination that satisfies the condition, if it exists. It will then, as a non-empty tuple, be converted to the boolean literal True. Otherwise, next will see that dropwhile is empty, and return the default value False.
Testing:
print(google([1, 2, 3, 4, 5], 8))
print(google([1, 2, 3, 4], 8))
Output:
True
False
Can you explain this python code?
Here how does L.sort(fun) work?
def fun(a, b):
return cmp(a[1], b[1])
L= [[2, 1], [4, 5, 3]]
L.sort(fun)
print L
From the official documentation:
The sort() method takes optional arguments for controlling the comparisons.
cmp specifies a custom comparison function of two arguments (list items)
which should return a negative, zero or positive number depending on whether
the first argument is considered smaller than, equal to, or larger than the
second argument: cmp=lambda x,y: cmp(x.lower(), y.lower()).
The default value is None.
So you are trying to control the comparison using your own function "fun". Which say compares the values present at 1st index of the lists inside list(nested lists).
if you try to test it separately you will get -1 as the a[1] is smaller than b[1]
clearly and hence the output is "[[2,1],[4,5,3]]" which is already sorted
a = [2,1]
b = [4,5,3]
cmp(a[1], b[1])
You can give it a try changing value at 1st index something like this and you will understand how it is working.
Something like this
def fun(a,b):
return cmp(a[1], b[1])
L=[[2,6],[4,5,3]]
L.sort(fun)
print L
I hope this will help.
In Python, I know the pythonic way to check if a list is empty is
if not a:
# do things with empty list
To check if a list is not empty then, we would do:
if a:
# do things with my list
How would we check, simultaneously (as read), if two lists then are not empty?
if a and b:
# do things with my two lists
The above does not seem to work, and I'm unsure what (a and b) actually means. For a = [2], b = [1,3], (a and b) = [1,3]. What is the and operator actually doing here? If I end up reducing b = [] at some point, (a and b) = [] even though a is not empty.
Edit: My use case goes something like
while (a and b are not empty):
modify a
modify b
I would have naively thought that since if a checks if a list is not empty, if a and b would check if neither were empty, which is not the case.
It's working fine. For a = [2] and b = [1, 3], a and b is returning [1, 3] which is truthy, exactly as you would expect, because True and True is True. When you change b to [] it returns [], which is falsy, again exactly as you would expect, because True and False is False. So if a and b does exactly what you want.
What is actually happening is that and is returning the value that decided the truth of the expression. and doesn't always evaluate both sub-expressions; when the first is falsy, the whole expression is falsy and the second doesn't need to be evaluated, and therefore isn't. This is called short-circuiting. or behaves similarly (skipping evaluating the second part if the first part is truthy). Wherever and or or is able to make its decision, it returns that value.
Another way of looking at it: bool(a) and bool(a) == bool(a and b) in Python.
a and b is correct.
and returns the second argument if the first is true.
You can do this
if len(a) and len(b):
#do something
I think what you want is
>>> a, b = list(), list()
>>> while not (a and b):
... a.append(1)
... b.append(2)
...
>>> a, b
([1], [2])
>>>
and operator is compare two boolean values
bool([]) == False
so [] and b always return []; no matter what b is.
To build on kindall's answer - you could also concatenate the lists before doing the truthiness test:
a = []
b = []
c = [1]
bool(a + b) # False
bool(a + b + c) # True
Of course this would come with a performance penalty if you were doing something where that mattered.
Is there a way to get the parent list, if some element is given? For instance, I have two lists a and b, and I want
def func(a,b):
mx = max(a[0], b[0]);
mn = min(a[0], b[0]);
return (the list that corresponds to (mx, mn) in the order)
Edit: for the above example, a simple if else is enough; but I wonder how to do it if I am dealing with many lists, and want to return, say, the name of the lists in the order of comparison? One solution I can come up with is use numpy sorting, which uses n log(n) sorting algorithms. Is there faster way?
Edit: Probably using numpy sorting is the way.
No, it is not possible. But you can get the list corresponding the maximum of the first elements, with conditional expression, like this
a, b = [1, 2], [2, 1]
c = a if a[0] > b[0] else b
print c
# [2, 1]
So, your function can be written as
def func(a,b):
return a if a[0] > b[0] else b
Since you mentioned numpy, simply use argmin and argmax.
def func(a,b):
lists = (a, b)
vals = np.array([a[0], b[0]])
return ( lists[np.argmax(vals)], lists[np.argmin(vals)] )
This can easily be generalised to more than two lists, and if all lists are of the same length, func can elegantly work on a 2dim array, e.g.:
def func(arr):
return ( arr[np.argmax(arr[:,0])], arr[np.argmin(arr[:,0])] )
You can use the key parameter of the max function.
import operator
def func(a,b):
return max(a, b, key=operator.itemgetter(0))