Let's say I have a list like:
my_list = [[1,2,3],[4,5,6],[7,8,9]]
How do I alter every value in the list without doing?:
for x in range(0, 3):
for y in range(0, 3):
my_list[x][y] = -my_list[x][y]
I have tried to simplify this by doing
my_list = [[[-a, -b, -c] for [a, b, c] in d] for d in my_list]
but the values remain the same.
Another option is to use the built-in map
function:
>>> my_list = [[1,2,3],[4,5,6],[7,8,9]]
>>> neg = lambda x: -x
>>> f = lambda x: map(neg, x)
>>> map(f, my_list)
[[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]
Many answers are about creating altered copy of list, but literal meaning of question is about in-place modification of list.
Here is my version of best-of-breed in-place list altering solution:
def alter_elements(lst, func):
for i, item in enumerate(lst):
if isinstance(item, list):
alter_elements(item, func)
else:
lst[i] = func(item)
Test run:
>>> sample = [[1,2,3],[4,5,6],[7,8,9]]
>>> alter_elements(sample, lambda x: -x)
>>> print sample
>>> [[-1, -2, -3], [-4, -5, -6], [-7, -8, -9]]
No list copies. No hardcoded bounds. No list comprehensions with side-effects.
It's possible to code a more general solution to this problem. The following works in Python 3.0, regardless of the level of nesting.
Let's define recursive_map
:
import collections
def recursive_map(f, iterable):
for e in iterable:
if isinstance(e, collections.Iterable):
yield recursive_map(f, e)
else:
yield f(e)
Now, the requested negation function can be coded as follows:
import functools
import operator
negate = functools.partial(recursive_map, operator.neg)
Thus, for some collection of arbitrarily nested iterables x
, we calculate its negation y
like this:
y = negate(x)
Addendum:
As noted by user chradcliffe, the above negate
function yields a generator which may contain other generators which ..., etc. To expand/evaluate all these generators, we need to apply list()
to all of them. So we define another general mapping function, this time one that works on the iterables themselves.
def recursive_iter_map(f, iterable):
def rec(e):
if isinstance(e, collections.Iterable):
return recursive_iter_map(f, e)
else:
return e
return f(map(rec, iterable))
Now,
all_lists = functools.partial(recursive_iter_map, list)
y = all_lists(negate(x))
will actually negate every element right away and return the complete list.
Note that we can regard a nested collection of iterables as a tree. Each iterable is a subtree, while non-iterables are leaves. Hence the first function I defined works on leaves, and the second function works on non-leaves.
By "alter" I assume you mean "negate" (but you should have said that).
I notice that you're iterating over each element of a two-dimensional array (a list of lists) and treating each element as a list of three elements... but in fact each element is just a number, in your question as stated. So I would do something like this:
my_list = [[-n for n in l] for l in my_list]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With