0

I want to write a nice one line list comprehension with "extend functionality", that also includes a conditional. here is what I have that works

nouns = []
[nouns.extend(value)/ for key, value in pos_dictionary.iteritems() 
    if key.startswith('NN') ]

ideally I write something nice like

nouns = [nouns.extend(value) for key, value in pos_dictionary.iteritems()
            if key.startswith('NN') ]

Which doesn't work because I haven't defined the list yet. The former isn't super horrible, essentially using the comprehension as functional List.iter statement. While I am new to python, this still doesn't seem like the correct style. If this is the proper style, I would appreciate some verification.

I am encountering this sceneario because I am looking to aggregate all the different types of Nouns Tags from the POS tagger (using NLTK) into a single list.

Edit: I agree it is nearly a duplicate, i didn't think if this as flattening a list, but now that it has been introduced as a possibility i can accept it. The one variant is that my example did include a conditional in the comprehension. Also I was inquiring as to the preferred idiomatic syntax, which while possibly open ended is a nice bit for a newbie to python.

akaphenom
  • 6,728
  • 10
  • 59
  • 109
  • 1
    A general remark - for this particular use case, the dictionary should maybe have a different structure: instead of iterating it and collecting all values for which the keys start with 'NN', just have a dictionary which either maps 'NN' to the (list of) values directly, or map 'NN' to the list of keys in `nouns` which start with `NN`. – Frerich Raabe Dec 18 '13 at 23:16

4 Answers4

3

Not everything is done best with a single list comprehension. While you could do

nouns = [x for key, value in pos_dictionary.iteritems() if key.startswith('NN') for x in value]

I really think that

nouns = []
for key, value in pos_dictionary.iteritems():
    if key.startswith('NN'):
        nouns += value

is far more redable.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
2

You can use itertools.chain.from_iterable() to stitch together a sequence of lists:

from itertools import chain

nouns = list(chain.from_iterable(value
    for key, value in pos_dictionary.iteritems()
    if key.startswith('NN')))
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

If you essentially want to run multiple list comprehensions that all contribute to the same final list, you can just create your separate list comprehensions like normal, and simple concat the lists then.

For example:

nouns1 = [value for key, value in pos_dictionary.iteritems() if key.startswith('NN')]
nouns2 = [value for somethingElse]
nouns3 = [value for andOneMore]
nouns = nouns1 + nouns2 + nouns3
poke
  • 369,085
  • 72
  • 557
  • 602
0
sum([value for key, value in pos_dictionary.iteritems() if key.startswith('NN') ],[])

although its slower ...

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • Using `sum()` to concatenate list has quadratic runtime. Please, never do this, and help me eliminating this anti-pattern from popping up everywhere. You should use either `itertools.chain.from_iterable()` or a list comprehenesion with two nested loops instead. – Sven Marnach Dec 18 '13 at 23:17
  • See [this question](http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python) for why using `sum` to flatten lists is a bad (though unfortunately popular) solution if the lists aren't very small. – Frerich Raabe Dec 18 '13 at 23:18
  • yeah I know... but it is easy to read and short, which sounded like his requirements) ... but yeah I would basically never do this in the real world... – Joran Beasley Dec 18 '13 at 23:18
  • 1
    I don't think it's easy to read. Summing over a list of lists doesn't make that much sense intuitively. It's a pity that `itertools.chain.from_iterable()` isn't simply a built-in called `flatten()`. – Sven Marnach Dec 18 '13 at 23:20
  • 1
    ok @SvenMarnach I wont post this answer again :P – Joran Beasley Dec 18 '13 at 23:20