The Python 2 documentation says:
Built-in Functions: map(function, iterable, ...)
Apply function to every item of iterable and return a list of the
results. If additional iterable arguments are passed, function must
take that many arguments and is applied to the items from all
iterables in parallel.
If one iterable is shorter than another it is assumed to be extended
with None items.
If function is None, the identity function is assumed; if there are
multiple arguments, map() returns a list consisting of tuples
containing the corresponding items from all iterables (a kind of
transpose operation).
The iterable arguments may be a sequence or any iterable object; the
result is always a list.
What role does this play in making a Cartesian product?
content = map(tuple, array)
What effect does putting a tuple anywhere in there have? I also noticed that without the map function the output is abc and with it, it's a, b, c.
I want to fully understand this function. The reference definitions is also hard to understand. Too much fancy fluff.
map isn't particularly pythonic. I would recommend using list comprehensions instead:
map(f, iterable)
is basically equivalent to:
[f(x) for x in iterable]
map on its own can't do a Cartesian product, because the length of its output list is always the same as its input list. You can trivially do a Cartesian product with a list comprehension though:
[(a, b) for a in iterable_a for b in iterable_b]
The syntax is a little confusing -- that's basically equivalent to:
result = []
for a in iterable_a:
for b in iterable_b:
result.append((a, b))
map doesn't relate to a Cartesian product at all, although I imagine someone well versed in functional programming could come up with some impossible to understand way of generating a one using map.
map in Python 3 is equivalent to this:
def map(func, iterable):
for i in iterable:
yield func(i)
and the only difference in Python 2 is that it will build up a full list of results to return all at once instead of yielding.
Although Python convention usually prefers list comprehensions (or generator expressions) to achieve the same result as a call to map, particularly if you're using a lambda expression as the first argument:
[func(i) for i in iterable]
As an example of what you asked for in the comments on the question - "turn a string into an array", by 'array' you probably want either a tuple or a list (both of them behave a little like arrays from other languages) -
>>> a = "hello, world"
>>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')
A use of map here would be if you start with a list of strings instead of a single string - map can listify all of them individually:
>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
Note that map(list, a) is equivalent in Python 2, but in Python 3 you need the list call if you want to do anything other than feed it into a for loop (or a processing function such as sum that only needs an iterable, and not a sequence). But also note again that a list comprehension is usually preferred:
>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
map creates a new list by applying a function to every element of the source:
xs = [1, 2, 3]
# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
ys.append(x * 2)
n-ary map is equivalent to zipping input iterables together and then applying the transformation function on every element of that intermediate zipped list. It's not a Cartesian product:
xs = [1, 2, 3]
ys = [2, 4, 6]
def f(x, y):
return (x * 2, y // 2)
# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
zs.append(f(x, y))
I've used zip here, but map behaviour actually differs slightly when iterables aren't the same size — as noted in its documentation, it extends iterables to contain None.
Simplifying a bit, you can imagine map() doing something like this:
def mymap(func, lst):
result = []
for e in lst:
result.append(func(e))
return result
As you can see, it takes a function and a list, and returns a new list with the result of applying the function to each of the elements in the input list. I said "simplifying a bit" because in reality map() can process more than one iterable:
If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items.
For the second part in the question: What role does this play in making a Cartesian product? well, map() could be used for generating the cartesian product of a list like this:
lst = [1, 2, 3, 4, 5]
from operator import add
reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))
... But to tell the truth, using product() is a much simpler and natural way to solve the problem:
from itertools import product
list(product(lst, lst))
Either way, the result is the cartesian product of lst as defined above:
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
(2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
(3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
(4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
(5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]
The map() function is there to apply the same procedure to every item in an iterable data structure, like lists, generators, strings, and other stuff.
Let's look at an example:
map() can iterate over every item in a list and apply a function to each item, than it will return (give you back) the new list.
Imagine you have a function that takes a number, adds 1 to that number and returns it:
def add_one(num):
new_num = num + 1
return new_num
You also have a list of numbers:
my_list = [1, 3, 6, 7, 8, 10]
if you want to increment every number in the list, you can do the following:
>>> map(add_one, my_list)
[2, 4, 7, 8, 9, 11]
Note: At minimum map() needs two arguments. First a function name and second something like a list.
Let's see some other cool things map() can do.
map() can take multiple iterables (lists, strings, etc.) and pass an element from each iterable to a function as an argument.
We have three lists:
list_one = [1, 2, 3, 4, 5]
list_two = [11, 12, 13, 14, 15]
list_three = [21, 22, 23, 24, 25]
map() can make you a new list that holds the addition of elements at a specific index.
Now remember map(), needs a function. This time we'll use the builtin sum() function. Running map() gives the following result:
>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]
REMEMBER:
In Python 2 map(), will iterate (go through the elements of the lists) according to the longest list, and pass None to the function for the shorter lists, so your function should look for None and handle them, otherwise you will get errors. In Python 3 map() will stop after finishing with the shortest list. Also, in Python 3, map() returns an iterator, not a list.
Python3 - map(func, iterable)
One thing that wasn't mentioned completely (although #BlooB kinda mentioned it) is that map returns a map object NOT a list. This is a big difference when it comes to time performance on initialization and iteration. Consider these two tests.
import time
def test1(iterable):
a = time.clock()
map(str, iterable)
a = time.clock() - a
b = time.clock()
[ str(x) for x in iterable ]
b = time.clock() - b
print(a,b)
def test2(iterable):
a = time.clock()
[ x for x in map(str, iterable)]
a = time.clock() - a
b = time.clock()
[ str(x) for x in iterable ]
b = time.clock() - b
print(a,b)
test1(range(2000000)) # Prints ~1.7e-5s ~8s
test2(range(2000000)) # Prints ~9s ~8s
As you can see initializing the map function takes almost no time at all. However iterating through the map object takes longer than simply iterating through the iterable. This means that the function passed to map() is not applied to each element until the element is reached in the iteration. If you want a list use list comprehension. If you plan to iterate through in a for loop and will break at some point, then use map.
Related
For example, I have three lists (of the same length)
A = [1,2,3]
B = [a,b,c]
C = [x,y,z]
and i want to merge it into something like:
[[1,a,x],[2,b,y],[3,c,z]].
Here is what I have so far:
define merger(A,B,C):
answer =
for y in range (len(A)):
a = A[y]
b = B[y]
c = C[y]
temp = [a,b,c]
answer = answer.extend(temp)
return answer
Received error:
'NoneType' object has no attribute 'extend'
It looks like your code is meant to say answer = [], and leaving that out will cause problems. But the major problem you have is this:
answer = answer.extend(temp)
extend modifies answer and returns None. Leave this as just answer.extend(temp) and it will work. You likely also want to use the append method rather than extend - append puts one object (the list temp) at the end of answer, while extend appends each item of temp individually, ultimately giving the flattened version of what you're after: [1, 'a', 'x', 2, 'b', 'y', 3, 'c', 'z'].
But, rather than reinventing the wheel, this is exactly what the builtin zip is for:
>>> A = [1,2,3]
>>> B = ['a', 'b', 'c']
>>> C = ['x', 'y', 'z']
>>> list(zip(A, B, C))
[(1, 'a', 'x'), (2, 'b', 'y'), (3, 'c', 'z')]
Note that in Python 2, zip returns a list of tuples; in Python 3, it returns a lazy iterator (ie, it builds the tuples as they're requested, rather than precomputing them). If you want the Python 2 behaviour in Python 3, you pass it through list as I've done above. If you want the Python 3 behaviour in Python 2, use the function izip from itertools.
To get a list of lists, you can use the built-in function zip() and list comprehension to convert each element of the result of zip() from a tupleto a list:
A = [1, 2, 3]
B = [4, 5, 6]
C = [7, 8, 9]
X = [list(e) for e in zip(A, B, C,)]
print X
>>> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Assuming you are doing this for class and not learning all of the tricks that make Python a great tool here is what you need. You had two problems, first if you want to extend then you do it in place but your desired result shows that you want to append, not extend
def merger(A,B,C):
answer = []
for y in range (len(A)):
a=A[y]
b=B[y]
c=C[y]
temp = [a,b,c]
answer.append(temp)
return answer
>>> answer
[[1, 'a', 'x'], [2, 'b', 'y'], [3, 'c', 'z']]
I was just wondering the same thing. I'm a total noob using code academy. This is what i came up to combine two lists index at index
toppings = ['pepperoni', 'pineapple', 'cheese', 'sausage', 'olives', 'anchovies', 'mushrooms']
prices = [2,6,1,3,2,7,2]
num_pizzas = len(toppings)
print("We sell "+str(num_pizzas)+" different kinds of pizza!")
***pizzas = list(zip(toppings, prices))***
print (pizzas)
the list pizzas printed out ...[('pepperoni', 2), ('pineapple', 6), ('cheese', 1), ('sausage', 3), ('olives', 2), ('anchovies', 7), ('mushrooms', 2)]
Sorry if this has already been asked, I couldn't find it anywhere. Basically how do I get 2 separate ranges within a list in Python.
If I want the 1st, 2nd, 5th and 6th elements of a list I know I can do this,
l = range(0,15)
l[1:3]+l[5:7]
but this assumes that l is easy to write. However I am scrapping something from a webpage using BeautifulSoup4, so I'm using soup.find_all (which gives me a list), so I can't simply write out 2 lists, l and concatenate them.
I want an answer that is something like
l = range(0,15)
l[1:3,5:7]
(but of course without the error) :)
This might be what you want. itemgetter creates a function that retrieves the listed indices:
>>> import operator
>>> snip = operator.itemgetter(1,2,5,6)
>>> snip(range(15))
(1, 2, 5, 6)
>>> snip('abcdefg')
('b', 'c', 'f', 'g')
>>> snip([1,2,3,4,5,6,7,8])
(2, 3, 6, 7)
I would do this with a function:
def multi_range(l, *args):
output = []
for indices in args:
output += l[indices[0]:indices[1]]
return output
So the first argument would be the list, and the rest of the parameters are tuples with the indices you're looking to pull. It would work fine with a long list name:
long_list_name = range(0, 15)
print multi_range(long_list_name, (1, 3), (5, 7))
>>> [1, 2, 5, 6]
l = range(0, 15)
print([l[i] for i in [1,2, 5,6]])
Not sure why you think l[1:3]+l[5:7] is hard, find_all returns a normal python list like any other.
Or using map:
l = range(0, 15)
print(list(map(l.__getitem__,(1,2,5,6))))
Is this OK?
indices = [1, 2, 5, 6]
selected = [l[i] for i in indices]
I'm new to Python and programming. Can someone explain the following codes in details?
def myzip(*seqs):
seqs = [list(S) for S in seqs]
res = []
while all(seqs):
res.append(tuple(S.pop(0) for S in seqs))
return res
>>> myzip([1, 2, 3], ['a', 'b', 'c'])
[(1, 'a'), (2, 'b'), (3, 'c')]
Especially, I don't understand the S is for element in a list (e.g. 1, 2...) or the list ([1, 2, 3]).
I think I need a detail explanation for each line.
In the list comprehension, S is assigned each of the arguments passed to the function; seqs is a list of arguments passed in, and you passed in two lists. So S is first bound to [1, 2, 3] then ['a', 'b', 'c'].
>>> seqs = [[1, 2, 3], ['a', 'b', 'c']]
>>> seqs[0]
[1, 2, 3]
The first line just makes sure that all arguments are turned into lists, explicitly, so that you can later on call list.pop(0) on each. This allows you to pass in strings, tuples, dictionaries, or any other iterable as an argument to this function:
>>> myzip('123', 'abc')
[('1', 'a'), ('2', 'b'), ('3', 'c')]
The while all(seqs): loop then iterates until there is at least one argument that is empty. In other words, the loop terminates when the shortest sequence has been exhausted:
>>> myzip('1', 'abc')
[('1', 'a')]
In the loop, the first element of each of the input arguments is removed from the list and added to res as a tuple. For the 2 input lists, that means that first (1, 'a') is added to res, followed by (2, 'b') then (3, 'c').
seqs is the list of two separate lists: [1,2,3] and ['a', 'b', 'c']
Now while all(seqs): will iterate through the elements of seqs - the two lists mentioned above.
We then create an empty list res and append to it tuple objects.
Each tuple object will progressively contain the first element of each of the list in seqs. pop(0) will return the first element and remove it from the list thus changing the list in place (lists are mutable).
Thus what you are doing is you are creating a list of tuples obtained by pairing the corresponding elements in both the lists.
When you say seqs = [list(S) for S in seqs], S refers to each of the list element in seqs. However, in this particular call to the function, since you are passing lists as elements this statement becomes redundant.
First You need to know what is zip function. Because this function is doing the same job as zip in python.
def myzip(*seqs):
First line says this function gets as many argument you want and all of them will be gather in one list as seqs. Usage like myzip([1, 2, 3], ['a', 'b', 'c']) gives you seqs = [[1, 2, 3], ['a', 'b', 'c']].
seqs = [list(S) for S in seqs]
Then you want to make sure every item in seqs are list items. This line convert every item to list. This is what list does. (Even '123' to ['1', '2', '3'])
res = []
while all(seqs):
res.append(tuple(S.pop(0) for S in seqs))
return res
In these four lines it pops first element of each S of seqs and creates a tuple for final result. The final result is a list (res = []).
In the loop condition: all(seqs) it checks if all elements of seqs are available. If one them goes empty it breaks the loop.
In side the loop, pop(0) removes the first element from S and return it as value S.pop(0). This way it updates all elements of seqs. for next loop.
tuple creates tuple like (1, 'a') out of all first elements. Next iteration is going to be `(2, 'b') because all first elements popped before.
All these tuples in a list res is its goal. res.append adds these tuple to the final result.
While looking for a pythonic way to rotate a matrix, I came across this answer. However there is no explanation attached to it. I copied the snippet here:
rotated = zip(*original[::-1])
How does it work?
>>> lis = [[1,2,3], [4,5,6], [7,8,9]]
[::-1] reverses the list :
>>> rev = lis[::-1]
>>> rev
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
now we use zip on all items of the rev, and append each returned tuple to rotated:
>>> rotated = []
>>> for item in zip(rev[0],rev[1],rev[2]):
... rotated.append(item)
...
>>> rotated
[(7, 4, 1), (8, 5, 2), (9, 6, 3)]
zip picks items from the same index from each of the iterable passed to it(it runs only up to the item with minimum length) and returns them as a tuple.
what is *:
* is used for unpacking all the items of rev to zip, so instead of manually typing
rev[0], rev[1], rev[2], we can simply do zip(*rev).
The above zip loop could also be written as:
>>> rev = [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
>>> min_length = min(len(x) for x in rev) # find the min length among all items
>>> rotated = []
for i in xrange(min_length):
items = tuple(x[i] for x in rev) # collect items on the same index from each
# list inside `rev`
rotated.append(items)
...
>>> rotated
[(7, 4, 1), (8, 5, 2), (9, 6, 3)]
Complementary to the explanations by Ashwini and HennyH, here's a little figure to illustrate the process.
First, the [::-1] slice operator reverses the list of list, taking the entire list (thus the first two arguments can be omitted) and using a step of -1.
Second, the zip function takes a number of lists and effectively returns a new list with rows and columns reversed. The * says that the list of lists is unpacked into several lists.
As can be seen, these two operations combined will rotate the matrix.
For my explination:
>>> m = [['a','b','c'],[1,2,3]]
Which when pretty-printed would be:
>>> pprint(m)
['a', 'b', 'c']
[1, 2, 3]
Firstly, zip(*m) will create a list of all the columns in m. As demonstrated by:
>>> zip(*m)
[('a', 1), ('b', 2), ('c', 3)]
The way this works is zip takes n sequences and get's the i-th element of each one and adds it to a tuple. So translated to our matrix m where each row is represented by a list contained within m, we essentially pass in each row to zip, which then gets the 1st element from each row puts all of them into a tuple, then gets every 2nd element from each row etc... Ultimately getting every column in m i.e:
>>> zip(['row1column1','row1column2'],['row2column1','row2column2'])
[('row1column1', 'row2column1'), ('row1column2', 'row2column2')]
Notice that each tuple contains all the elements in a specific column
Now that would look like:
>>> pprint(zip(*m))
('a', 1)
('b', 2)
('c', 3)
So effectively, each column in m is now a row. Hoever it isn't in the correct order (try imagine in your head rotating m to get the matrix above, it can't be done). This why it's necessary to 'flip' the original matrix:
>>> pprint(zip(*m[::-1]))
(1, 'a')
(2, 'b')
(3, 'c')
Which results in a matrix which is the equivalent of m rotated - 90 degrees.
Lets say I have the following list:
lst = [0,1,3,a,b,c]
I would like the final outcome to be all possible permutations of lst, but be 20 characters long.
I have looked and can only find examples that would create a final outcome that would be 6 or less in length.
Any ideas?
I think itertools.product is what you're looking for.
# A simple example
import itertools
lst = [0, 1]
print(list(itertools.product(lst, repeat=2)))
# [(0, 0), (0, 1), (1, 0), (1, 1)]
Note that itertools.product itself returns an itertools.product object, not a list.
# In your case
import itertools
lst = [0, 1, 3, a, b, c]
output = list(itertools.product(lst, repeat=20))
Are you sure you want all permutations? Assuming you want to reuse characters (not a permutation) that would be a list with a length of 6^20.
If you want one string of length 20 built from characters in that list, this should do the job:
from random import choice
''.join(choice(chars) for _ in range(length))
The problem is that permutations and combinations (if you use itertools) follow the definition that each result can only physically exist if it is of equal or lesser length than the originating list.
If you are suggesting that you want one of the valid results to be "013abc013abc013abc01", then you'll have to modify your list to just be 20 items long and be made up of those 6 values.
from itertools import permutations
i = [0,1,3,'a','b','c',0,1,3,'a','b','c',0,1,3,'a','b','c',0,1]
results = []
for a in permutations(i, 20):
results.append(a)
list(permutations(lst,x)) ; where lst is iterable (your input list) and x is the no of elements
for example:
In [8]: lst = [0, 1, 3, 'a', 'b', 'c']
In [9]: from itertools import permutations
In [10]: result=[list(permutations(lst,x)) for x in range(1,len(lst))]