tags:

views:

157

answers:

6

I could do this using an index but I thought there must be a cleaner way using list comprehensions. I'm a beginner. I hope it's not embarrassingly obvious. Thanks

for x in firstList:
    firstFunc(x)
    secondFunc(x)
    x = process(x)
    if x.discard == True:
        (get rid of x)
secondList.append(firstList)
+1  A: 

You know, your best solution is really to just initialize secondList how you like, and do all three functions in a regular loop, since they're all dependent and contain logic that is not just filtering (you say process sets attributes... I'm assuming you mean other than discard):

# If secondList not initialized...
secondList = []
for x in firstList:
    firstFunc(x)
    secondFunc(x)
    process(x)
    if not x.discard:
        secondList.append(x)

List comprehensions don't help too much here since you're doing processing in each function (they take a line or two off though; depends on what you're looking for in "clean" code). If all process() did was return True if the item should be in the new list, and False if the item should not be in the new list, then the below would really be better, IMO.


If firstFunc(x) and secondFunc(x) do change the result of x.discard after process(), and the result of process(x) is just x, I would do the following in your situation:

for x in firstList:
    firstFunc(x)
    secondFunc(x)
secondList = [ x for x in firstList if not process(x).discard ]

If the result of process(x) is different from x though, as your sample appears to indicate, you could also change that last line to the following:

interimList = [ process(x) for x in firstList ]
secondList = [ x for x in interimList if not x.discard ]

Note that if you wanted to append these results to secondList, use secondList.extend([...]).

Edit: I realized I erroneously wrote "do not" change, but I meant if they do change the result of process().

Edit 2: Cleanup description / code.

Walt W
`where` ?
SilentGhost
Why two loops when only once is necessary. That's not going to be faster and isn't really cleaner.
Lennart Regebro
@Lennart: Because firstFunc and secondFunc affect the output of process, and it's much clearer to separate them since that's important if you ask me.
Walt W
x is an object whose attributes are set by process(), so it's the same thing that is called.
Peter Stewart
I learned alot from all these answers.The answer to my question is that list comprehensions don't cleanly deal with this. If I'm expected to accept an answer, I'll accept Walt's, thanks for all the interest.
Peter Stewart
@Walt: In what way is it clearer two have two loops when you can have one? That's unclear and confusing if you ask me.
Lennart Regebro
@Lennart: Because until recently, we only knew that process(x) set the discard flag, and the other two altered x.
Walt W
@Walt: Yes, and once again, two loops are useless, you can do it in one, more cleanly. I see now you have added a version first where you do that. That is good, and how I would do it.
Lennart Regebro
@Lennart - If process(x) does not do anything except return True or False, it would be cleaner to use a list comprehension at the end, to show the separation of logic and filtering. But that's just me.
Walt W
A: 

Edit: process(x) is necessary for x.discard, meaning that the answer is:

No there is no cleaner way. And the way you are doing it is already clean.

Old answer:

Not really, no. You can make this:

def process_item(x):
    firstFunc(x)
    secondFunc(x)
    x = process(x)

def test_item(x):
    return x.discard == False

list = [process_item(x) for x in firstList if test_item(x)]

But that is not cleaner, and also it requires x.discard to be set before you process it, which it doesn't seem to be from your code.

List comprehensions are not "cleaner". They are shorter ways of writing simple list processing. You list processing involves three steps. That's not really "simple". :)

Lennart Regebro
The OP says firstFunc and secondFunc are necessary for process(), which fills in discard . . . this code won't work.
Walt W
OP has a broken API. he's not doing it proper way.
SilentGhost
A: 

a few things:

  • you cannot append a list, you need to use extend.
  • no need for == True bit, use just if x.discard:
  • you'd rather create a new list with values that you don't want to discard and don't pollute your loop with removal.

so you'd have something along the lines:

tmp = []
for x in first_list:
    x = process(x)
    if not x.discard:
        tmp.append(x)
second_list.extend(tmp)

list comprehension would obviously more pythonic, though:

[i for i in first_list if not process(i).discard]
SilentGhost
thanks for the corrections (extend and ==)
Peter Stewart
A: 

Sounds like

def allProcessing(x)
  firstFunc(x)
  secondFunc(x)
  return !(process(x).discard)

newList = filter(allProcessing, oldList)
unwind
`!process` ?
SilentGhost
I meant with the parens, I added some.
unwind
what version of python used `!` as a negation operator?
SilentGhost
A: 

Write this as two list comprehensions, one which assembles the data that might need filtering, and another which does the filtering. Make firstFunc and secondFunc return x (as process does), and then you can write it like so:

unfilteredList = [secondFunc(firstFunc(x)) for x in firstList]
secondList = [x for x in unfilteredList if not x.discard]
aem
+2  A: 

Just a thought, and it does little for documentation, but why not try:

def masterFunc(x):
    firstFunc(x)
    secondFunc(x)
    process(x)
    return x.discard

secondList = [ x for x in firstList if masterFunc(x) ]

Good news: does what you asked, strictly speaking. Bad news: it hides firstFunc, secondFunc, and process

It sounds like you already have trouble with side-effects and command/query separation in the example, so I'm thinking that this hack is not as noble as cleaning up the code a bit. You might find that some methods need inverted (x.firstFunc() instead of firstFunc(x)) and others need broken up. There may even be a nicer way than 'x.discard' to deal with filtering.

tottinge