views:

109

answers:

2

If have a list of dictionary items like so:

L = [{"a":1, "b":0}, {"a":3, "b":1}...]

I would like to split these entries based upon the value of "b", either 0 or 1.

A(b=0) = [{"a":1, "b":1}, ....]
B(b=1) = [{"a":3, "b":2}, .....]

I am comfortable with using simple list comprehensions, and i am currently looping through the list L two times.

A = [d for d in L if d["b"] == 0]
B = [d for d in L if d["b"] != 0]

Clearly this is not the most efficient way.

An else clause does not seem to be available within the list comprehension functionality.

Can I do what I want via list comprehension?

Is there a better way to do this?

I am looking for a good balance between readability and efficiency, leaning towards readability.

Thanks!

update: thanks everyone for the comments and ideas! the most easiest one for me to read is the one by Thomas. but i will look at Alex' suggestion as well. i had not found any reference to the collections module before.

+4  A: 

Don't use a list comprehension. List comprehensions are for when you want a single list result. You obviously don't :) Use a regular for loop:

A = []
B = []
for item in L:
    if item['b'] == 0:
        target = A
    else:
        target = B
    target.append(item)

You can shorten the snippet by doing, say, (A, B)[item['b'] != 0].append(item), but why bother?

Thomas Wouters
you don't need to compare `item['b']` with `0` in this particular case.
SilentGhost
That depends on what the possible values of item['b'] are, but yes, typically you would use 'if item['b']:' instead, and swap the if and else suites.
Thomas Wouters
+3  A: 

If the b value can be only 0 or 1, @Thomas's simple solution is probably best. For a more general case (in which you want to discriminate among several possible values of b -- your sample "expected results" appear to be completely divorced from and contradictory to your question's text, so it's far from obvious whether you actually need some generality;-):

from collections import defaultdict

separated = defaultdict(list)
for x in L:
  separated[x['b']].append(x)

When this code executes, separated ends up with a dict (actually an instance of collections.defaultdict, a dict subclass) whose keys are all values for b that actually occur in dicts in list L, the corresponding values being the separated sublists. So, for example, if b takes only the values 0 and 1, separated[0] would be what (in your question's text as opposed to the example) you want as list A, and separated[1] what you want as list B.

Alex Martelli