fix: _cut_iter yields wrong-length parts when step > n
partition()/chunks() on an iterator (_cut_iter) only correctly skipped step items between parts when step <= n. For step > n, slicing an n-length pool by pool[step:] silently clips to an empty list, then islice(it, step) pulled step (not n) fresh items into the pool instead of first discarding the step - n items between parts. This produced wrong-length, wrong-content chunks that diverged from the Sequence code path (_cut_seq) for the same input, e.g. list(range(10)) vs iter(range(10)) with n=2, step=3. Branch on step < n to keep the existing sliding-window logic, and for step >= n explicitly discard the gap before taking the next pool.
This commit is contained in:
1 parent
f15f2b80fb
commit
a12abd3a5e
2 files changed
+16
No files matched your search
@@ -363,8 +363,12 @@ def _cut_iter(drop_tail, n, step, seq):
|
|||||||
if len(pool) < n:
|
if len(pool) < n:
|
||||||
break
|
break
|
||||||
yield pool
|
yield pool
|
||||||
|
if step < n:
|
||||||
pool = pool[step:]
|
pool = pool[step:]
|
||||||
pool.extend(islice(it, step))
|
pool.extend(islice(it, step))
|
||||||
|
else:
|
||||||
|
take(step - n, it) # discard the gap between parts
|
||||||
|
pool = take(n, it)
|
||||||
if not drop_tail:
|
if not drop_tail:
|
||||||
for item in _cut_seq(drop_tail, n, step, pool):
|
for item in _cut_seq(drop_tail, n, step, pool):
|
||||||
yield item
|
yield item
|
||||||
|
|||||||
@@ -170,6 +170,18 @@ def test_chunks():
|
|||||||
assert lchunks(2, 1, [0, 1, 2, 3]) == [[0, 1], [1, 2], [2, 3], [3]]
|
assert lchunks(2, 1, [0, 1, 2, 3]) == [[0, 1], [1, 2], [2, 3], [3]]
|
||||||
assert lchunks(3, 1, iter(range(3))) == [[0, 1, 2], [1, 2], [2]]
|
assert lchunks(3, 1, iter(range(3))) == [[0, 1, 2], [1, 2], [2]]
|
||||||
|
|
||||||
|
def test_partition_step_gt_n():
|
||||||
|
# Iterator code path must skip step - n items between parts,
|
||||||
|
# matching the Sequence code path, when step > n.
|
||||||
|
assert lpartition(2, 3, iter(range(10))) == lpartition(2, 3, list(range(10)))
|
||||||
|
assert lpartition(2, 3, iter(range(10))) == [[0, 1], [3, 4], [6, 7]]
|
||||||
|
|
||||||
|
def test_chunks_step_gt_n():
|
||||||
|
# Iterator code path must skip step - n items between parts,
|
||||||
|
# matching the Sequence code path, when step > n.
|
||||||
|
assert lchunks(2, 3, iter(range(10))) == lchunks(2, 3, list(range(10)))
|
||||||
|
assert lchunks(2, 3, iter(range(10))) == [[0, 1], [3, 4], [6, 7], [9]]
|
||||||
|
|
||||||
def test_partition_by():
|
def test_partition_by():
|
||||||
assert lpartition_by(lambda x: x == 3, [1,2,3,4,5]) == [[1,2], [3], [4,5]]
|
assert lpartition_by(lambda x: x == 3, [1,2,3,4,5]) == [[1,2], [3], [4,5]]
|
||||||
assert lpartition_by('x', 'abxcd') == [['a', 'b'], ['x'], ['c', 'd']]
|
assert lpartition_by('x', 'abxcd') == [['a', 'b'], ['x'], ['c', 'd']]
|
||||||
|
|||||||
Reference in new issue
Block a user