4

Let's say, we have and list of objects in variable called "articles", each object has a member "tags" (which is simple list).

Expected output: all tags in all articles, joined in a single list.

In multiple lines, solution would be:

arr = []
for article in articles:
    for tag in article.tags:
       arr.append(tag)

Now, how can we write this in single line instead of 4?

This syntax is invalid:

arr = [tag for tag in article.tags for article in articles]

Thanks!

1

6 Answers 6

11

It's invalid because article doesn't exist by the time the first loop is parsed.

arr = [tag for article in articles for tag in article.tags]
Sign up to request clarification or add additional context in comments.

1 Comment

Tied for best answer and answered the longest time ago. Pick this one, OP.
5

You are actually looping in the order that you don't want to order:

what you want is:

result = [ tag for article in articles for tag in article.tags ]

To translate what you were doing in your example would be:

for tag in article.tags:
    for article in articles:
       #code

which doesn't make much sense.

Comments

4

Perhaps

arr = [tag for tag in (a.tags for a in articles)]

2 Comments

I think a generator expression (() instead of []) for the inner loop would be better.
in this case, arr output will be: [[a1_tag1, a1_tag2], [a2_tag1, a2_tag2]]
2

Try this:

import itertools
it = itertools.chain.from_iterable(article.tags for article in articles)
l  = list(it) # if you really need a list and not an iterator

1 Comment

Cool! Wouldn't (article.tags for article in articles) i.e. generator be even better?
2

This is already answered multiple times, but it can be helpful to break lines and indent:

arr = [tag 
       for article in articles
           for tag in article.tags]

This has the advantage of

  1. Making it more readable if you needed to do some kind of projection on tag (like getting (tag.name, tag.description, tag.count) or some other tuple or transformation of a tag)
  2. Making the syntax for nested generator expressions more readable to a beginner
  3. Making complex nested generator expressions more readable

Comments

2

If you want unique tags, you might be better served by

import operator
tags = reduce(operator.__or__, (set(article.tags) for article in articles), set())

Edit:

  • For Python 3, you would need to

    from functools import reduce
    
  • The initializer set() is returned if the sequence is empty, rather than throwing an error.

1 Comment

This one is very elegant solution. There were no uniqueness requirement - I have planned to convert the list to set later, but your code is one step ahead ;) Few possible problems - reduce is removed from Python 3 standard library (not a big deal, but it means something) and "if the sequence is empty, an exception is raised".

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.