How to conditionally replace items in a list
I wanted to replace items in a list based on a specific condition. For example, given a list of numbers, I want to replace all items that are negative with zero.
Naive way
At first, I thought of something like this:
mylist = [111, -222, 333, -444]
newlist = []
for item in mylist:
if item < 0:
item = 0
newlist.append(item)
mylist = newlist
print mylist
Which gave me the expected results:
[111, 0, 333, 0]
Better way?
Then I tried using Python's enumerate
(see my previous example) built-in function to replace the item in-line. This seems to be a more elegant solution to me. Is there a better way? How would you do it?
mylist = [111, -222, 333, -444]
for (i, item) in enumerate(mylist):
if item < 0:
mylist[i] = 0
print mylist
Results:
[111, 0, 333, 0]
Related posts
- An example using Python's groupby and defaultdict to do the same task — posted 2014-10-09
- python enum types — posted 2012-10-10
- Python data object motivated by a desire for a mutable namedtuple with default values — posted 2012-08-03
- How to sort a list of dicts in Python — posted 2010-04-02
- Python setdefault example — posted 2010-02-09
Comments
How about
mylist = [x*(x>=0) for x in mylist]
Or readably: map(lambda x: 0 if x<0 else x, mylist)
Alejandro and Harsh,
Thanks for the feedback. I definitely like the conciseness of list comprehensions and the map/lambda combination. I suppose the "if x<0 else x" expression allows for other general conditional tests besides my specific example. As another alternative, I could combine that expression with a list comprehension and write: mylist = [0 if x<0 else x for x in mylist]
My bigger question is, what should I do if I have multiple statements within my "if" condition? For example, the actual code that I was writing was this:
for (i, parent) in enumerate(parent_list):
....if parent['id'] == parent_pk:
........parent.setdefault(child_field, []).append(child)
........parent_list[i] = parent
(note, I replaced the leading spaces with periods due to the limitations in my commenting system. yeah, I know, I ought to update my commenting system. I was kind of hoping Django would do it for me).
If I tried to make this into one list comprehension, I think I would start to lose readability. I really like the functional/declarative style of Python programming but I don't know how to migrate complex loop+conditional logic. Do I need to break it up into multiple declarative statements?
I suppose, that you variant with "max" is more readable:
map(lambda x: max(0,x), mylist)
For multiple ifs, you can write separate function and pass it to the map or in the list comprehension instead of lambda.
Some offtopic.
Please, add an atom link (http://www.saltycrane.com/feeds/latest/) to the HTML template, and any rss reader can autodiscover your feed.
Alexander, Thanks for the comments. Passing a separate function to the map or list comprehension sounds good. I will have to keep that in mind the next time I come across something similar.
Regarding the feed link, is there something wrong with my Atom at the bottom of my right sidebar? Is there a problem because I use a relative URL?
alright! good job...hehehe
i found a little "blip" here...once i commented i couldn't go back to the original page to read my own comment...hmmm...
me2icecream,
yeah, I know this is a problem. unfortunately, I don't know how to fix it. if I figure out anything, I will make the change.
You can simply do it like
[ 0 if x < 0 else x for x in mylist ]
I posted a question / answer along the same lines as this blog post over at Stackoverflow. My answer uses a try-except
approach.