0

Recently, I found a piece of python code posted by Paul Panzer (the best answer) in Python "Stars and Bars"

import itertools
bars = [0, 0, 0, 0, 0, 8]
result = [[bars[j+1] - bars[j] - 1 for j in range(5)] for bars[1:-1] in itertools.combinations(range(1, 8), 4)]

I couldn't understand the slices of variable bars[1:-1] inside the for loop. Please help.

What is the relationship bewteen bars and the member of the iterable object in the loop?

qxwd123
  • 15
  • 4
  • Please, explain more clearly "What is the relationship bewteen bars and the member of the iterable object in the loop?" – Cloud Cho Jun 16 '20 at 02:33
  • Within my comperhension of loop in python, the variable after the `for` keywoard will be assigned to each member of the iterable object during the iteration. My question is the relationship the already defined variable `bars` and the loop variable. – qxwd123 Jun 16 '20 at 07:51

2 Answers2

1

In the expression:

for foo in itertools.combinations(range(1, 8), 4)

itertools.combinations(range(1, 8), 4) is yielding sequences of 4 items, which are being assigned to the variable foo. You can see this if you just print foo in a loop:

>>> for foo in itertools.combinations(range(1, 8), 4):
...     print(foo)
...
(1, 2, 3, 4)
(1, 2, 3, 5)
(1, 2, 3, 6)
(1, 2, 3, 7)
(1, 2, 4, 5)
(1, 2, 4, 6)
(1, 2, 4, 7)
(1, 2, 5, 6)
(1, 2, 5, 7)
(1, 2, 6, 7)
(1, 3, 4, 5)
(1, 3, 4, 6)
(1, 3, 4, 7)
(1, 3, 5, 6)
(1, 3, 5, 7)
(1, 3, 6, 7)
(1, 4, 5, 6)
(1, 4, 5, 7)
(1, 4, 6, 7)
(1, 5, 6, 7)
(2, 3, 4, 5)
(2, 3, 4, 6)
(2, 3, 4, 7)
(2, 3, 5, 6)
(2, 3, 5, 7)
(2, 3, 6, 7)
(2, 4, 5, 6)
(2, 4, 5, 7)
(2, 4, 6, 7)
(2, 5, 6, 7)
(3, 4, 5, 6)
(3, 4, 5, 7)
(3, 4, 6, 7)
(3, 5, 6, 7)
(4, 5, 6, 7)

If you replace foo with a list slice that is 4 elements long, then those 4 elements are instead assigned to that slice:

>>> bars = [0, 0, 0, 0, 0, 8]
>>> for bars[1:-1] in itertools.combinations(range(1, 8), 4):
...     print(bars)
...
[0, 1, 2, 3, 4, 8]
[0, 1, 2, 3, 5, 8]
[0, 1, 2, 3, 6, 8]
[0, 1, 2, 3, 7, 8]
[0, 1, 2, 4, 5, 8]
[0, 1, 2, 4, 6, 8]
[0, 1, 2, 4, 7, 8]
[0, 1, 2, 5, 6, 8]
[0, 1, 2, 5, 7, 8]
[0, 1, 2, 6, 7, 8]
[0, 1, 3, 4, 5, 8]
[0, 1, 3, 4, 6, 8]
[0, 1, 3, 4, 7, 8]
[0, 1, 3, 5, 6, 8]
[0, 1, 3, 5, 7, 8]
[0, 1, 3, 6, 7, 8]
[0, 1, 4, 5, 6, 8]
[0, 1, 4, 5, 7, 8]
[0, 1, 4, 6, 7, 8]
[0, 1, 5, 6, 7, 8]
[0, 2, 3, 4, 5, 8]
[0, 2, 3, 4, 6, 8]
[0, 2, 3, 4, 7, 8]
[0, 2, 3, 5, 6, 8]
[0, 2, 3, 5, 7, 8]
[0, 2, 3, 6, 7, 8]
[0, 2, 4, 5, 6, 8]
[0, 2, 4, 5, 7, 8]
[0, 2, 4, 6, 7, 8]
[0, 2, 5, 6, 7, 8]
[0, 3, 4, 5, 6, 8]
[0, 3, 4, 5, 7, 8]
[0, 3, 4, 6, 7, 8]
[0, 3, 5, 6, 7, 8]
[0, 4, 5, 6, 7, 8]

Same 4 elements, but now they're assigned to the middle of bars, as referenced by the slice expression bars[1:-1].

In the context of your comprehension, bars will have those values as it goes through the outer loop. The inner comprehension generates another list that is based on the value of bars in that outer loop.

Samwise
  • 68,105
  • 3
  • 30
  • 44
  • Thanks, I can vaguely understand the procedure from the output of which you presented. But, is there any document may related to this? – qxwd123 Jun 16 '20 at 07:55
  • And I also found that if using line compression for the second piece of code, which is `[bars for bars[1:-1] in itertools.combinations(range(1, 8), 4)]`, the output will be a list contain 35 repeated `[0, 4, 5, 6, 7, 8]`. Could you explain it to me? – qxwd123 Jun 16 '20 at 08:01
0

bars[1:-1] basically means all the list items from index 1 to -1, where -1 means the last index.

So if bars = [1,2,3,4,5], bars[1:-1] = [2,3,4]

Red
  • 26,798
  • 7
  • 36
  • 58