Python equivalent to Ruby Array.each method - python

In Python what is equivalent to Ruby's Array.each method? Does Python have a nice and short closure/lambda syntax for it?
[1,2,3].each do |x|
puts x
end

Does Python have a nice and short closure/lambda syntax for it?
Yes, but you don't want it in this case.
The closest equivalent to that Ruby code is:
new_values = map(print, [1, 2, 3])
That looks pretty nice when you already have a function lying around, like print. When you just have some arbitrary expression and you want to use it in map, you need to create a function out of it with a def or a lambda, like this:
new_values = map(lambda x: print(x), [1, 2, 3])
That's the ugliness you apparently want to avoid. And Python has a nice way to avoid it: comprehensions:
new_values = [print(x) for x in values]
However, in this case, you're just trying to execute some statement for each value, not accumulate the new values for each value. So, while this will work (you'll get back a list of None values), it's definitely not idiomatic.
In this case, the right thing to do is to write it explicitly—no closures, no functions, no comprehensions, just a loop:
for x in values:
print x

The most idiomatic:
for x in [1,2,3]:
print x

You can use numpy for vectorized arithmetic over an array:
>>> import numpy as np
>>> a = np.array([1, 2, 3])
>>> a * 3
array([3, 6, 9])
You can easily define a lambda that can be used over each element of an array:
>>> array_lambda=np.vectorize(lambda x: x * x)
>>> array_lambda([1, 2, 3])
array([1, 4, 9])
But as others have said, if you want to just print each, use a loop.

There are also libraries that wrap objects to expose all the usual functional programming stuff.
PyDash http://pydash.readthedocs.org/en/latest/
underscorepy (Google github underscore.py)
E.g. pydash allows you to do things like this:
>>> from pydash import py_
>>> from __future__ import print_function
>>> x = py_([1,2,3,4]).map(lambda x: x*2).each(print).value()
2
4
6
8
>>> x
[2, 4, 6, 8]
(Just always remember to "trigger" execution and/or to un-wrap the wrapped values with .value() at the end!)

without need of an assignment:
list(print(_) for _ in [1, 2, 3])
or just
[print(_) for _ in [1, 2, 3]]

Related

Use splat operator in multidimensional list index

Say I have the list
a = [[1, 2, 3],
[4, 5, 6]]
and I have an index that I want to use to access an element of this list.
index = [1,2]
I want to use something like
a[*index] = 9
to mean a[index[0]][index[1]] = 9, but this doesn't work and neither does a[**index] = 9. Is there a similar way to do this without having a chain of index calls?
I would like a method to do this without using any libraries that must be imported.
First of all a[c, d, e] is equivalent to a[(c, d, e)] which is equivalent to a.__getitem__((c, d, e)). Note the double parentheses. Any __getitem__ implementation that wants to play nice with the Python data model always expects exactly one (explicit) argument.
That's why unpacking values from index inside the [] does not make much sense. a[*index] will give you a SyntaxError and a.__getitem__(*index) gives you a TypeError (because you are providing too many arguments).
Standard Python lists expect integer arguments to __getitem__, but numpy supports indexing with tuples (a numpy array still only takes exactly one argument for __getitem__, but it's allowed to be a tuple).
Demo:
>>> import numpy as np
>>> a = np.array([[1,2,3], [4,5,6]])
>>> a[(1,2)]
6
Of course, you can omit the parentheses, because
>>> a[1,2]
6
is exactly equivalent.
You can use reduce(), which is part of the standard library:
>>> a = [[1, 2, 3],
... [4, 5, 6]]
>>> index = [1, 2]
>>> import functools, operator
>>> functools.reduce(operator.getitem, index, a)
6
Or, you can write your own class that supports that kind of multi-dimensional indexing:
import functools, operator
class Matrix:
def __init__(self, lst):
self._lst = lst
def __getitem__(self, index):
return functools.reduce(operator.getitem, index, self._lst)
a = Matrix([[1, 2, 3],
[4, 5, 6]])
index = [1, 2]
print(a[index]) # -> 6
Otherwise, this is not possible using just lists and without loops or other functions.

Concatenating list results from multiple functions

So, basically I've got a few functions that return tuples. Essentially of the form:
def function():
return (thing, other_thing)
I want to be able to add several of these functions together in a straightforward way, like this:
def use_results(*args):
"""
Each arg is a function like the one above
"""
results = [test() for test in args]
things = magic_function(results)
other_things = magic_function(results)
Basically I have the data structure:
[([item_1, item_1], [item_2, item_2]), ([item_3, item_3], [item_4, item_4])]
and I want to turn it into:
[[item_1, item_1, item_3, item_3], [item_2, item_2, item_4, item_4]]
It seems like there's probably a nice pythonic way of doing this with a combination of zip and *, but it's not quite coming to me.
Oh, I feel kind of silly. I found an answer quickly after posting the question. I'm going to still keep this up in case there's a better solution though:
>>> import operator
>>> results = [([1,1], [2,2]), ([3,3], [4,4])]
>>> map(operator.add, *results)
[[1, 1, 3, 3], [2, 2, 4, 4]]
Without importing any module, just built-in methods:
>>> results = [([1,1], [2,2]), ([3,3], [4,4])]
>>> [x+y for x,y in zip(*results)]
[[1, 1, 3, 3], [2, 2, 4, 4]]
Or even this way as well:
>>> map(lambda s,t:s+t, *results)

python: print i for i in list

When I printed a list, I got a syntax error when using this method:
print i for i in [1,2,3]
I knew this is ok when using this method:
for i in [1, 2, 3]:
print i
and I knew that
(i for i in [1, 2, 3])
is a generator object, but I just don't get it that why
print i for i in [1, 2, 3]
does't work. Can anyone give me a clue?
The list comprehension syntax x for x in ... requires brackets around it. That's a syntactic rule of Python, just like requiring indentation, or requiring a colon after if or whatever. i for i in [1, 2, 3] by itself is not valid syntax. You need either [i for i in [1, 2, 3]] (for a list comprehension) or (i for i in [1, 2, 3]) (for a generator comprehension).
In Python 2, print is a statement, not an expression or a function, so you can't use it directly in a comprehension. Use this trick:
def f(x): print x
[f(i) for i in [1,2,3]]
Note that (f(i)...) doesn't work because this just creates a generator which would call f() if you iterated over it. The list comprehension [] actually invokes f().
[EDIT] If you use Python > 2.6, you can achieve the same using
from __future__ import print_function
[print(i) for i in [1, 2, 3]]
Note the () around the argument to print.
The list comprehension syntax ([expression for loop]) is a shorthand loop syntax for producing a list.
You are not producing a list, you want to print items in a loop. Since you are not producing a python list, you have to use a regular loop.
Alternatively, since all you are doing is printing the items on separate lines, just add the newlines yourself:
print '\n'.join(i for i in [1, 2, 3])
This produces the same output as:
for i in [1, 2, 3]:
print i
If you use Python 3, or use from __future__ import print at the top of your module and so use the print() function, you can send all values to the function in one call, and tell print() to use newlines in between:
values = [1, 2, 3]
print(*values, sep="\n")
As an expression (in the grammar):
[i for i in [1, 2, 3]] is a list comprehension.
(i for i in [1, 2, 3]) is a generator expression.
But i for i in [1, 2, 3] by itself is a syntax error, and that's just the way it is. There must be something surrounding it. Unless you have ( or [ around it, it's not a valid expression, because the for keyword is not valid at that point.
Inside the print statement, it wants an expression.
(As a red herring, func(i for i in [1, 2, 3]) is permitted as an expression, being a function call with the first argument being a generator expression.)
Print is not a function, it's a statement, and you can't have them in expressions. Just use a regular loop as you don't want to produce a list, that a list comprehension does. In theory you can do (not that you should. at all):
from __future__ import print_function
[print(my_item) for my_item in [1,2,3,4]]
1
2
3
4
Out[26]:
[None, None, None, None]
This is invalid python syntax. The i for i in [1, 2, 3] is only valid in a list or generator comprehension, ie. surrounded by [] or () respectively.
You'll want to use:
print '\n'.join(str(i) for i in [1, 2, 3])

zipWith analogue in Python?

What is the analogue of Haskell's zipWith function in Python?
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
map()
map(operator.add, [1, 2, 3], [3, 2, 1])
Although a LC with zip() is usually used.
[x + y for (x, y) in zip([1, 2, 3], [3, 2, 1])]
You can create yours, if you wish, but in Python we mostly do
list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ]
as Python is not inherently functional. It just happens to support a few convenience idioms.
You can use map:
>>> x = [1,2,3,4]
>>> y = [4,3,2,1]
>>> map(lambda a, b: a**b, x, y)
[1, 8, 9, 4]
A lazy zipWith with itertools:
import itertools
def zip_with(f, *coll):
return itertools.starmap(f, itertools.izip(*coll))
This version generalizes the behaviour of zipWith with any number of iterables.
Generally as others have mentioned map and zip can help you replicate the functionality of zipWith as in Haskel.
Generally you can either apply a defined binary operator or some binary function on two list.An example to replace an Haskel zipWith with Python's map/zip
Input: zipWith (+) [1,2,3] [3,2,1]
Output: [4,4,4]
>>> map(operator.add,[1,2,3],[4,3,2])
[5, 5, 5]
>>> [operator.add(x,y) for x,y in zip([1,2,3],[4,3,2])]
[5, 5, 5]
>>>
There are other variation of zipWith aka zipWith3, zipWith4 .... zipWith7. To replicate these functionalists you may want to use izip and imap instead of zip and map.
>>> [x for x in itertools.imap(lambda x,y,z:x**2+y**2-z**2,[1,2,3,4],[5,6,7,8],[9,10,11,12])]
>>> [x**2+y**2-z**2 for x,y,z in itertools.izip([1,2,3,4],[5,6,7,8],[9,10,11,12])]
[-55, -60, -63, -64]
As you can see, you can operate of any number of list you desire and you can still use the same procedure.
I know this is an old question, but ...
It's already been said that the typical python way would be something like
results = [f(a, b) for a, b in zip(list1, list2)]
and so seeing a line like that in your code, most pythonistas will understand just fine.
There's also already been a (I think) purely lazy example shown:
import itertools
def zipWith(f, *args):
return itertools.starmap(f, itertools.izip(*args))
but I believe that starmap returns an iterator, so you won't be able to index, or go through multiple times what that function will return.
If you're not particularly concerned with laziness and/or need to index or loop through your new list multiple times, this is probably as general purpose as you could get:
def zipWith(func, *lists):
return [func(*args) for args in zip(*lists)]
Not that you couldn't do it with the lazy version, but you could also call that function like so if you've already built up your list of lists.
results = zipWith(func, *lists)
or just like normal like:
results = zipWith(func, list1, list2)
Somehow, that function call just looks simpler and easier to grok than the list comprehension version.
Looking at that, this looks strangely reminiscent of another helper function I often write:
def transpose(matrix):
return zip(*matrix)
which could then be written like:
def transpose(matrix):
return zipWith(lambda *x: x, *matrix)
Not really a better version, but I always find it interesting how when writing generic functions in a functional style, I often find myself going, "Oh. That's just a more general form of a function I've already written before."

proper use of list comprehensions - python

Normally, list comprehensions are used to derive a new list from an existing list. Eg:
>>> a = [1, 2, 3, 4, 5]
>>> [i for i in a if i > 2]
[3, 4, 5]
Should we use them to perform other procedures? Eg:
>>> a = [1, 2, 3, 4, 5]
>>> b = []
>>> [b.append(i) for i in a]
[None, None, None, None, None]
>>> print b
[1, 2, 3, 4, 5]
or should I avoid the above and use the following instead?:
for i in a:
b.append(i)
You should indeed avoid using list comprehensions (along with dictionary comprehensions, set comprehensions and generator expressions) for side effects. Apart from the fact that they'd accumulate a bogus list and thus waste memory, it's also confusing. I expect a list comprehension to generate a (meaningful) value, and many would agree. Loops, on the other hand, are clearly a sequence of statements. They are expected to kick off side effects and generate no result value - no surprise.
From python documentation:
List comprehensions provide a concise way to create lists. Common
applications are to make new lists
Perhaps you want to learn more about reduce(), filter() and map() functions.
In the example you give it would make the most sense to do:
b = [i for i in a]
if for some reason you wanted to create b. In general, there is some common sense that must be employed. If using a comprehension makes your code unreadable, don't use it. Otherwise go for it.
Only use list comprehensions if you plan to use the created list. Otherwise you create it just for the GC to throw it again without ever being used.
So instead of [b.append(i) for i in a] you should use a proper for loop:
for i in a:
b.append(i)
Another solution would be through a generator expression:
b += (i for i in a)
However, if you want to append the whole list, you can simply do
b += a
And if you just need to apply a function to the elements before adding them to the list, you can always use map:
b += map(somefunc, a)
b = []
a = [1, 2, 3, 4, 5]
b.extend (a)

Categories