Convert Assignment Cycle to Understanding

Converting a loop into an understanding is simple enough:

mylist = [] for word in ['Hello', 'world']: mylist.append(word.split('l')[0]) 

to

 mylist = [word.split('l')[0] for word in ['Hello', 'world']] 

But I'm not sure how to proceed when a loop involves assigning a value to a link.

 mylist = [] for word in ['Hello', 'world']: split_word = word.split('l') mylist.append(split_word[0]+split_word[1]) 

And the understanding is as follows:

 mylist = [word.split('l')[0]+word.split('l')[1] for word in ['Hello', 'world']] 

This evaluates word.split('l') several times, while the loop only evaluates it once and saves the link. I tried the following:

 mylist = [split_word[0]+split_word[1] for word in ['Hello', 'world'] with word.split('l') as split_word] 

which does not work because with does not work this way and:

 mylist = [split_word[0]+split_word[1] for word in ['Hello', 'world'] for split_word = word.split('l')] 

which doesn't work either. I know about unpacking through * and ** , but I'm not sure where this will fit here. Is it possible to turn these types of loops into understanding, I hope, in a neat way?

+6
source share
2 answers

You cannot directly translate this cycle into understanding. Understandings that are expressions can only contain expressions, and assignments are statements.

However, this does not mean that there are no options.

First, at the cost of calling split twice, you can simply do this:

 mylist = [word.split('l')[0]+word.split('l')[1] for word in ['Hello', 'world']] 

But you do not want to call split twice.


The most common way is to use the generator expression chain (with one list comprehension at the end) to transform things:

 words = (word.split('l') for word in ['Hello', 'world']) mylist = [w[0]+w[1] for w in words] 

If you really want to combine all this into one expression, you can:

 mylist = [w[0]+w[1] for w in (word.split('l') for word in ['Hello', 'world'])] 

But if you really don’t need it to be in an expression, perhaps it is more readable so as not to do it.


A more specific way in this case is to replace w[0]+w[1] with something equivalent that does not need to be referenced by w twice:

 mylist = [''.join(word.split('l')[:2]) for word in ['Hello', 'world']] 

And you can always generalize this as well. You can turn any expression into a function, which means that you can avoid evaluating any part of it by passing it as an argument to that function. If there is no function that does what you want, write:

 def join_up(split_word): return split_word[0]+split_word[1] mylist = [join_up(word.split('l')) for word in ['Hello', 'world']] 

If you need to do everything in one expression without repeating any work, this may not be very pretty:

 mylist = [(lambda split_word: split_word[0]+split_word[1])(word.split('l')) for word in ['Hello', 'world']] 

But ultimately, if I already had a function lying around that did what I needed, I would use a solution to generate chains of generators.

Or, of course, just keep it in an explicit loop; There is nothing wrong with for loops, and if an intermediate temporary variable makes the code more clear, there is no better way to do this than with an assignment operator.

+9
source

Be creative.

 mylist = [''.join(word.split('l')[:2]) for word in ['Hello', 'world']] 

...

 mylist = [''.join(operator.itemgetter(0, 1)(word.split('l'))) for word in ['Hello', 'world']] 
+6
source

Source: https://habr.com/ru/post/986339/


All Articles