Basic Python manipulation of nested list - python

For the following nested list, Lst, I need to keep the first inner list, square the second, and cube the last one.
Lst = [[1,2,3],[2,3,4],[3,4,5]]
My current code is squaring all the nested list in the Lst.
list(map(lambda lst: list(map(lambda x: x**2, lst)), Lst))
How can I fix this? I just started learning Python.

Since you're not doing the same operation on each nested list, you shouldn't use map() for the top-level list. Just make a list of results of different mappings for each.
[Lst[0], list(map(lambda x: x**2, lst[1])), list(map(lambda x: x**3, lst[2]))]
However, there's an obvious pattern to this, so you can generalize it using enumerate() and a list comprehension:
[list(map(lambda x: x**i, sublist)) for i, sublist in enumerate(Lst, 1)]

[list(map(lambda x: x**i, l)) for i,l in enumerate(Lst, 1)]
[[1, 2, 3], [4, 9, 16], [27, 64, 125]]

Your processing obviously needs to take into account where in the list you are. Forcing this into a one-liner makes it more dense than it really needs to be, but see if you can follow along with pencil and paper.
[[x if i == 0 else x**2 if i == 1 else x**3 for x in Lst[i]] for i in range(3)]
Demo: https://ideone.com/o8y0ta
... Or, as cleverly suggested in Barmar's answer,
[[x**i for x in Lst[i]] for i in range(3)]

Try indexing the outer list and then call the map function on each index
def square(number) :
return number ** 2
def cube(number) :
return number ** 3
lst = [[1,2,3],[2,3,4],[3,4,5]]
lst[0] = lst[0]
lst[1] = list(map(square, lst[1]))
lst[2] = list(map(cube, lst[2]))
print(lst)

Related

Unexpected output in nested list comprehension in Python

I have a nested list comprehension, when I print the output, it gives me generator object, I was expecting a tuple.
vector = [[1,2],[2,3],[3,4]]
res = (x for y in vector for x in y if x%2 == 0)
print(res)
I thought since I have small bracket for res assignment, I thought the result will be tuple, but it gives me a generator object.
But when I use a traditional approach, it gives me a list.
lst = []
for y in vector:
print(y)
for x in y:
print(x)
if x%2 == 0:
lst.append(x)
print(lst)
It looks clear here that it gives a list there is no confusion here in the second one, but the first one is little confusing as why it gives a generator object.
Python doesn't know that you want your generator expression to be a list until you make it one. ;^)
vector = [[1,2],[2,3],[3,4]]
res = list((x for y in vector for x in y if x%2 == 0)) # use generator expression to make a list
print(res)
Output:
[2, 2, 4]

python map function (+ lambda) involving conditionals (if)

I'm curious if it's possible to do something with the map()function that I can do via list comprehension.
For ex, take this list comp:
example_list = [x*2 for x in range(5) if x*2/6. != 1]
obviously, this gives me [0, 2, 4, 8].
How do I make the equivalent using the map() function? Doing this gives me a syntax error.
example_map = map(lambda x:x*2 if x*2/6. != 1, range(5))
Just trying to get a better understanding of how to use this function.
You'll have to wrap the map around a filter around the list:
example_map = map(lambda x: x*2, filter(lambda x: x*2/6. != 1, range(5)))
Alternatively, you could filter your map rather than maping your filter.
example_map = filter(lambda x: x/6. != 1, map(lambda x: x*2, range(5)))
Just remember that you're now filtering the RESULT rather than the original (i.e. lambda x: x/6. != 1 instead of lambda x: x*2/6. != 1 since x is already doubled from the map)
Heck if you really want, you could kind of throw it all together with a conditional expression
example_map = map(lambda x: x*2 if x*2/6. != 1 else None, range(5))
But it'll leave you with [0, 2, 4, None, 8]. filter(None, example_map) will drop the Nones and leave you [0, 2, 4, 8] as expected.
Along side the other answers that suggests some solutions the reason of your Syntax Error is that map function :
Apply function to every item of iterable and return a list of the results.
So the result is in a same length as your iterable.and if you use if statement you need to specify an else too.
>>> map(lambda x:x*2 if x*2/6. != 1 else None, range(5))
[0, 2, 4, None, 8]
And as an alternative way you can use itertools.ifilter to filter your iterable :
>>> from itertools import ifilter
>>> map(lambda x:x*2,ifilter(lambda x: x*2/6. != 1,range(5)))
[0, 2, 4, 8]
Note that as you don't need the result of filtered list and you just want to pass it to map it's more efficient that use ifilter because it returns a generator and you can save much memory for long lists ;) (its all in python 2 and in python 3 filter returns generator)
you can do it at two stages, first stage by applying filter on the list and the second stage by applying mapping function on the output list
list(map(lambda x:x*2, filter(lambda x: x*2/6 != 1 , [x for x in range(5)])))
[0, 2, 4, 8]

Duplicate list items using list comprehension

I would like to duplicate the items of a list into a new list, for example
a=[1,2]
b=[[i,i] for i in a]
gives [[1, 1], [2, 2]], whereas I would like to have [1, 1, 2, 2].
I also found that I could use:
b=[i for i in a for j in a]
but it seemed like overkill to use two for loops. Is it possible to do this using a single for loop?
You want itertools.chain.from_iterable(), which takes an iterable of iterables and returns a single iterable with all the elements of the sub-iterables (flattening by one level):
b = itertools.chain.from_iterable((i, i) for i in a)
Combined with a generator expression, you get the result you want. Obviously, if you need a list, just call list() on the iterator, but in most cases that isn't needed (and is less efficient).
If, as Ashwini suggests, you want each item len(a) times, it's simple to do that as well:
duplicates = len(a)
b = itertools.chain.from_iterable([i] * duplicates for i in a)
Note that any of these solutions do not copy i, they give you multiple references to the same element. Most of the time, that should be fine.
Your two-loop code does not actually do what you want, because the inner loop is evaluated for every step of the outer loop. Here is an easy solution:
b = [j for i in a for j in (i, i)]
You could use xrange and using a generator expression or a list comprehension
b = (x for x in a for _ in xrange(2))
b = [x for x in a for _ in xrange(2)]
if you do not mind the order:
>>> a = [1,2]
>>> a * 2
[1, 2, 1, 2]

How to perform operation on elements of list which depend on previous elements?

Using map can do operations of current element in list:
l = [1,2,3,4,5,6];
print(list(map(lambda x: x*2, l)))
# gives [2, 4, 6, 8, 10, 12]
In above, multiply by 2 is done for all elements in l. But how to mulitiply by 2 an element in l, only if previous value in l is odd? Can use map for this?
For example to get:
[1,4,3,8,5,12] % only 2, 4 and 6 from l are multiplyied by 2, because before them there are odd numbers 1,3,5.
You can use map if you do it on an enumerated version:
print(list(map(lambda index,x: x*2 if index > 1 and l[index-1] & 1 else x, enumerate(l))))
However, as you might have noticed, that's really not very readable. It's better to just use a list comprehension or a for loop:
print([x*2 if index > 1 and l[index-1] & 1 else x
for index, x in enumerate(l)])
You can use zip in combination with map:
print(l[:1] + list(map(lambda x: x[1]*2 if x[0] & 1 else x[1], zip(l, l[1:]))))
Note that I had to explicitly prepend the first element of the list because it has no previous element to test.
You can zip the list along with a sliced copy of the list to pair all of the items:
>>> l = [1, 2, 3, 4, 5, 6]
>>> zip(l, l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
You can use something callable to track your previous value. Depending on how abstract you want this:
prev = [0]
def callback(x):
val = ((prev[0] % 2) + 1) * x
prev[0] = x
return val
print list(map(callback, l))
I realise that it was probably just a trivial example, but thought it worth mentioning that in your example case the condition "if the previous value is odd" is the same as "if the current value is even" (at least for your sample input). In which case I would just use
print([x if x&1 else x*2 for x in l])
For the more general case and assuming the condition may be more complex than just "previous item is odd", I would take a few lines to express the solution clearly. Python's generators are a good fit:
>>> def double_if_prev_odd(l):
... prev_odd = False # initial condition for 1st element
... for x in l:
... yield x**2 if prev_odd else x
... prev_odd = x&1
...
>>> list(double_if_prev_odd(l))
[1, 4, 3, 16, 5, 36]

[python]: problem about passing map() with a func and 2 lists with different dimensions

suppose I got a list, say
lst1 = [1,2,3,4]
and another list, say
lst2 = [8,9]
and a func, say
func = lambda x,y: x+y
what I want to do is to produce a list whose element is the sum of lst1's element and lst2's.
i.e., I want to produce a lst with lst1 and lst2, and lst should be
[1+8+9, 2+8+9, 3+8+9, 4+8+9].
how can I do it with map()?
>>> map(lambda x: x + sum(lst2), lst1)
[18, 19, 20, 21]
>>> map(lambda x, y: x + y, lst1, itertools.repeat(sum(lst2), len(lst1)))
[18, 19, 20, 21]
Your func is simply add operator so you can use 'add' from operator module the following way:
from operator import add
lst = [1,2,3,4]
sLst = [8,9]
map(lambda x: add(x, sum(sLst)), lst)
>>> [18,19,20,21]
It is ok to use map - but usually it is not so fast as simple list comprehension that also looks pretty clear:
from operator import add
lst = [1,2,3,4]
sLst = [8,9]
[add(x, sum(sLst)) for x in lst]
>>> [18,19,20,21]

Categories

Resources