SaltyCrane Blog — Notes on JavaScript and web development

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]

Comments


#1 Alejandro commented on :

How about

mylist = [x*(x>=0) for x in mylist]


#2 Harsh commented on :

Or readably: map(lambda x: 0 if x<0 else x, mylist)


#3 Sofeng commented on :

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?


#4 Alexander Artemenko commented on :

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.


#5 Alexander Artemenko commented on :

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.


#6 Sofeng commented on :

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?


#7 Angela commented on :

alright! good job...hehehe


#8 Angela commented on :

i found a little "blip" here...once i commented i couldn't go back to the original page to read my own comment...hmmm...


#9 Eliot commented on :

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.


#10 Mushfiq commented on :

You can simply do it like

[ 0 if x < 0 else x for x in mylist ]


#11 ashok baktha commented on :

I posted a question / answer along the same lines as this blog post over at Stackoverflow. My answer uses a try-except approach.