python reduce error? - python

The following is my python code:
>>> item = 1
>>> a = []
>>> a.append((1,2,3))
>>> a.append((7,2,4))
>>> sums=reduce(lambda x:abs(item-x[1]),a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 1 argument (2 given)
>>>
How can I fix it?
Thanks!

Your lambda takes only one argument, but reduce requires a function that takes two arguments. Make your lambda take two arguments.
Since you didn't say what you want this code to do, I'll just guess:
the_sum=reduce(lambda x,y:abs(y[1]-x[1]),a)

Your problem itself is a bit unclear. Anyway, i have taken just assumption--
>>> a = []
>>> a.append((1,2,3))
>>> a.append((7,2,4))
>>> a
[(1, 2, 3), (7, 2, 4)] # list of tuples
I am assuming that you might be interested in getting the sum of all the elements in the list. If that is the problem then that could be solved in 2 steps
1) The first step should be to flatten the list.
2) And then add all the elements of the list.
>>> new_list = [y for x in a for y in x] # List comprehension used to flatten the list
[1, 2, 3, 7, 2, 4]
>>> sum(new_list)
19
One liner
>>> sum([y for x in a for y in x])
19
Another assumption, if your problem is to minus every element of tuple by item in the list then use this:
>>> [tuple(map(lambda y: abs(item - y), x)) for x in a]
[(0, 1, 2), (6, 1, 3)] # map function always returns a list so i have used tuple function to convert it into tuple.
If the problem is something else then please elaborate.
PS: Python List comprehension is far better and efficient than anything else.

reduce expects the function it is given to accept 2 arguments. For every item in the iterable it will pass the function the current item, and the previous return value from the function. So, getting the sum of a list is reduce(lambda: x,y: x+y, l, 0)
If I understand correctly, to get the behavior you were trying to get, change the code to:
a_sum = reduce(lambda x,y: x + abs(item-y[1]), a, 0)
But I might be mistaken as to what you were trying to get.
Further information is in the reduce function's docstring.

Related

what is the best way to calculate the power of several ints in a list using python3?

So what I have is a list of integers such as [2, 2, 2, 3, ..., n] the length of the list can be anywhere from 1 to 100. What I need to do is calculate the powers of all the numbers. This should be super easy but there is also the stipulation that you must raise each number to the power of the next number to the power of the next number and so on. FOR EXAMPLE: if the list contained [2, 3, 4] first I would need to calculate the power of 3^4 and then 2^(answer of 3^4). If the list is longer it would need to calculate the value for all of them. The example above [2, 3, 4] should return 2^81 which should be something like 2417851639229258349412352 according to wolfram. Any help would be awesome even if its just an algorithm (I can figure out the code from there) I've just been struggling to come up with a sufficient algorithm for some time now.
here is some code I have now...
temp = []
length = 0
for num in powernumbers:
for index in num:
if index.isdigit():
temp.append(index)
length = len(temp)
if length > 0:
for j in reversed(range(len(temp))):
_temp = math.pow(int(temp[j-1]), int(temp[j]))
#THE ABOVE CODE WILL ONLY WORK FOR A LIST OF LEN 2
print(_temp)
#needs math.pow(0,(math.pow(1,(math.pow(2,...)))))
print("TEMP:", temp)
Once again any help is super appreciated!
You could use functools.reduce with reversed list:
>>> from functools import reduce
>>> l = [2, 3, 4]
>>> reduce(lambda x, y: y**x, reversed(l))
2417851639229258349412352
reduce takes two arguments: function and iterable. Then it will cumulatively apply the function to reduce the iterable to single value. First parameter of the function is reduced value and second parameter is item from iterable. Since we want to process the list in reverse order we're using reversed so that 3**4 will be executed first.
Note that on Python 2 reduce is a builtin so there's no need to import anything.
>>> numbers = [2,3,4] # your list
>>> result = 1
>>> for n in reversed(numbers):
result = n**result
>>> result
2417851639229258349412352
>>>
first initialize the result on 1, then go through the list in reverse order raising the number to the previous result, which the first time is 1 resulting for this example in
result = 4**1 -> 4
result = 3**4 -> 81
result = 2**81 -> 2417851639229258349412352
but be aware, this Nested exponentials will grow very very fast, and you more likely would get a memory error for the insanely big numbers
>>> result = 1
>>> powers = [2,2,2,2,2,2]
>>> for n in reversed(powers):
result = n**result
Traceback (most recent call last):
File "<pyshell#60>", line 2, in <module>
result = n**result
MemoryError
>>>
Pop the last element off of the list, then go through the list backwards and keep exponentiating.
powernumbers = [2, 3, 4]
result = powernumbers.pop()
for num in powernumbers[::-1]:
result = num**result
The result:
>>> result
2417851639229258349412352

Creating a generator in python

I am trying to create a generator that prints the next number on the list. This is a racket version:
(require racket/generator)
(define my-gen
(generator
(_)
(for ([x (list 1 2 3))])
(yield x)))
)
How it should work:
(my-gen) -> 1
(my-gen) -> 2
I also want to be able to use the function directly without having to initialize it at a specific point, so having the generator be the function that actually returns the result, as opposed to something like this:
l = [1, 2, 3]
def myGen():
for element in l:
yield element
g = myGen()
print(next(g))
What is the best way to go about this in python?
# Generator expression
(exp for x in iter)
# List comprehension
[exp for x in iter]
Iterating over the generator expression or the list comprehension will do the same thing. However, the list comprehension will create the entire list in memory first while the generator expression will create the items on the fly, so you are able to use it for very large.
In above generator will create generator object, to get data you have iterate or filter over it. It may be help you
Using functools.partial:
>>> import functools
>>> l = [1, 2, 3]
>>> my_gen = functools.partial(next, iter(l))
>>> my_gen()
1
>>> my_gen()
2
>>> my_gen()
3
>>> my_gen()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Is this what you are looking for?
number = 1
while(number<500 +1):
print('(my-gen) ->', number)
number +=1

What is an expression such as [d[k] for k in d] called?

Python newbie here.
In learning about Python I have come across some very nice, succinct bits of code such as:
[d[k] for k in d]
I can see immediately that there are lots of possibilities for these kinds of expressions ("these kinds" meaning contained inside a []).
I'm unsure of what this kind of expression is called, and so I am having trouble searching for information on how to use it. Would be great for some knowledgeable folks to direct me toward the part of the Python docs, or other resources, that discusses these, and perhaps provide some suggestions of how to effectively use them.
The code you posted is an expression, not a statement.
It is commonly called a list comprehension and its basic structure is:
[item for item in iterable if condition]
where the if condition clause is optional. The result is a new list object created from the items in iterable (possibly filtered by if condition):
>>> [x for x in (1, 2, 3)] # Get all items in the tuple (1, 2, 3).
[1, 2, 3]
>>> [x for x in (1, 2, 3) if x % 2] # Only get the items where x % 2 is True.
[1, 3]
>>>
In addition, there are dictionary comprehensions:
{key:value for key, value in iterable if condition}
and set comprehensions:
{item for item in iterable if condition}
which each do the same thing as the list comprehension, but produce dictionaries or sets respectively.
Note however that you need Python 2.6 or greater to use these constructs.
A final tool that you should be aware of is a generator expression:
(item for item in iterable if condition)
Similar to the list comprehension, it creates a generator object which produces its items lazily (one at a time as they are needed):
>>> (x for x in (1, 2, 3))
<generator object <genexpr> at 0x02811A80>
>>> gen = (x for x in (1, 2, 3))
>>> next(gen) # Advance the generator 1 position.
1
>>> next(gen) # Advance the generator 1 position.
2
>>> next(gen) # Advance the generator 1 position.
3
>>> next(gen) # StopIteration is raised when there are no more items.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>

What's the difference between lists enclosed by square brackets and parentheses in Python?

>>> x=[1,2]
>>> x[1]
2
>>> x=(1,2)
>>> x[1]
2
Are they both valid? Is one preferred for some reason?
Square brackets are lists while parentheses are tuples.
A list is mutable, meaning you can change its contents:
>>> x = [1,2]
>>> x.append(3)
>>> x
[1, 2, 3]
while tuples are not:
>>> x = (1,2)
>>> x
(1, 2)
>>> x.append(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'
The other main difference is that a tuple is hashable, meaning that you can use it as a key to a dictionary, among other things. For example:
>>> x = (1,2)
>>> y = [1,2]
>>> z = {}
>>> z[x] = 3
>>> z
{(1, 2): 3}
>>> z[y] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Note that, as many people have pointed out, you can add tuples together. For example:
>>> x = (1,2)
>>> x += (3,)
>>> x
(1, 2, 3)
However, this does not mean tuples are mutable. In the example above, a new tuple is constructed by adding together the two tuples as arguments. The original tuple is not modified. To demonstrate this, consider the following:
>>> x = (1,2)
>>> y = x
>>> x += (3,)
>>> x
(1, 2, 3)
>>> y
(1, 2)
Whereas, if you were to construct this same example with a list, y would also be updated:
>>> x = [1, 2]
>>> y = x
>>> x += [3]
>>> x
[1, 2, 3]
>>> y
[1, 2, 3]
One interesting difference :
lst=[1]
print lst // prints [1]
print type(lst) // prints <type 'list'>
notATuple=(1)
print notATuple // prints 1
print type(notATuple) // prints <type 'int'>
^^ instead of tuple(expected)
A comma must be included in a tuple even if it contains only a single value. e.g. (1,) instead of (1).
They are not lists, they are a list and a tuple. You can read about tuples in the Python tutorial. While you can mutate lists, this is not possible with tuples.
In [1]: x = (1, 2)
In [2]: x[0] = 3
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/user/<ipython console> in <module>()
TypeError: 'tuple' object does not support item assignment
Another way brackets and parentheses differ is that square brackets can describe a list comprehension, e.g. [x for x in y]
Whereas the corresponding parenthetic syntax specifies a tuple generator: (x for x in y)
You can get a tuple comprehension using: tuple(x for x in y)
See: Why is there no tuple comprehension in Python?
The first is a list, the second is a tuple. Lists are mutable, tuples are not.
Take a look at the Data Structures section of the tutorial, and the Sequence Types section of the documentation.
Comma-separated items enclosed by ( and ) are tuples, those enclosed by [ and ] are lists.
( thanx Robert for clarification, below is only in case of using listcomprehensions : )
! another very important difference is that with round brackets we will have a generator and so the memory consumption is much lower in comparison to list with square brackets
esspecially when you deal with big lists - generator will eat not only significantly less memory but also will take much less time 'cause you will not need to prebuilt objects in list

How to get filter to work with a lambda taking multiple arguments?

Using Python, am finding it difficult to get filter() to work with lambda for cases where more than 1 argument needs to be passed as is the case in the following snippet:
max_validation = lambda x,y,z: x < y < z
sequence1 = [1,4,8]
filter(max_validation, sequence1)
It raises the following error:
TypeError: <lambda>() takes exactly 3 arguments (1 given)
Please suggest as to what am doing wrong here.
It's a little bit difficult to figure out exactly what you're trying to do. I'm going to interpret your question, then provide an answer. If this is not correct, please modify your question or comment on this answer.
Question
I have sequences that are exactly three elements long. Here's one:
sequence1 = [1, 4, 8]
I want to ensure that the first element is less than the second element, which should in turn be less than the third element. I've written the following function to do so:
max_validation = lambda x, y, z: x < y < z
How do I apply this using filter? Using filter(max_validation, sequence1) doesn't work.
Answer
Filter applies your function to each element of the provided iterable, picking it if the function returns True and discarding it if the function returns False.
In your case, filter first looks at the value 1. It tries to pass that into your function. Your function expects three arguments, and only one is provided, so this fails.
You need to make two changes. First, put your three-element sequence into a list or other sequence.
sequences = [[1, 4, 8], [2, 3, 9], [3, 2, 3]]
max_validation = lambda x: x[0] < x[1] < x[2] and len(x) == 3
I've added two other sequences to test. Because sequences is a list of a list, each list gets passed to your test function. Even if you're testing just one sequence, you should use [[1, 4, 8]] so that the entire sequence to test gets passed into your function.
I've also modified max_validation so that it accepts just one argument: the list to test. I've also added and len(x) == 3 to ensure that the sequences are only 3 elements in length
The function passed to filter() only gets a single argument passed to it, which is the current element in the iterable being iterated.. If you need something fancier than that then filter() won't do.
Straight from the docs of Python Filters
Note that filter(function, iterable)
is equivalent to [item for item in
iterable if function(item)] if
function is not None and [item for
item in iterable if item] if function
is None.
So, you can just process single arguments with Python filters. That effectively means you cannot use filters for the your example. You would have to write custom-code for the same.
It's possible to do this using a closure:
>>> def foo(a,b):
... def bar(c):
... return a+b+c
... return bar
...
>>> x = foo(1,2)
>>> x(3)
6
>>> y = foo(100,0)
>>> y(1)
101
>>> x(1)
4
I hope you are aware of?
>>> max([1, 4, 8])
8
filter() takes a single argument. In your case, it will take 1. Then 4. Then 8.
This would work for sequences of any length:
all(x < y for x, y in zip(seq, seq[1:]))
What does there happens?
For sequence 1, 2, 3... you take sequences 1, 2, 3... and 2, 3, 4... and zip them together to sequence (1, 2), (2, 3), ...
Then you check if statement 'x < y' holds for every pair.
And this will work for any associative rule you want to check.
Useful links:
slices in Python
zip in Python docs
all in Python docs
I think all others didn't get the point. the error message is for lambda function not for the filter. You should rather call it this way:
filter(max_validation, *sequence1)
add a star on the list transform it into three arguments, then it will work.
I'm in agreement with both #walkingpendulum and #Wesley, depending on the interpretation of the actual problem statement. So parsing through the ambiguity in the problem statement:
If you're sequentially comparing one item to its previous value in an iterable object, a lambda expression is overkill, just
use a list comprehension:
[1 if i < i+1 else 0 for i in sequence1]
If you're comparing objects, then just compare them -- a lambda expression wouldn't work firstly because you're only passing one argument where the lambda expression you defined you're passing three and lambda is generally applied across an iterable object. To compare objects, there are simple constructs for that:
sequence1 == some_other_sequence
and
x, y, z = 1, 2, 3
x < y < z
And lastly, if you want to apply a lambda expression to an iterable object, map can get you there: (arbitrary lambda function)
map(lambda x: x > 1, sequence1)
Otherwise #walkingpendulum and #Wesley cover the other interpretations
You could change
max_validation = lambda x,y,z: x < y < z
to
max_validation = lambda (x,y,z): x < y < z

Categories

Resources