【问题标题】:Delete every other element with slicing使用切片删除所有其他元素
【发布时间】:2021-07-26 08:45:28
【问题描述】:

考虑一下:

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这些是 Python 中删除元素的正确语句:

numbers[0:2] = []
numbers[3:5] = []

但是下面的说法是不允许的:

numbers[::2] = []

ValueError: 尝试将大小为 0 的序列分配给大小为 5 的扩展切片

是什么阻止了 Python 中的这种语句?

【问题讨论】:

  • 对于连续切片,分配不同长度的可迭代对象的语义相对清晰。对于非连续切片,则更少:想象一下numbers[::2] = [1],这应该是什么意思?
  • 我想我没有看到歧义。不就是[1, 1, 1, 3, 1, 5, 1, 7, 1, 9]吗?替代解释是什么?
  • numbers[0:2]slice,而 numbers[::2]extended slice。如果问题真的是关于是什么阻止了这一点,而不是为什么阻止了这一点,那么这就是答案
  • @tdy 那么numbers[::2] = [1, 2]的解释是什么?
  • @tdy 说列表是numbers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],然后我们执行numbers[::2] = [1, 2]。它模棱两可的原因是因为分配可能以不同的方式发生,无论是[1, 0, 2, 0, 1, 0, 2, 0, 1, 0][1, 0, 2, 0, None, 0, None, 0, None, 0][1, 0, 2, 0, 2, 0, 2, 0, 2, 0][1, 0, 1, 0, 1, 0, 1, 0, 2, 0][[1, 2], 0, [1, 2], 0, [1, 2], 0, [1, 2], 0, [1, 2], 0]。与执行 numbers[3:9] = [1, 2] 不同,它只有 1 个含义,即删除项目 3:9 然后将 [1,2] 放在其位置产生 [0, 0, 0, 1, 2, 0]

标签: python


【解决方案1】:

ValueError: 尝试将大小为 0 的序列分配给大小为 5 的扩展切片

是什么阻止了 Python 中的这种语句?

documentation 中指出,对于存在显式步骤的情况(在您的情况下为2),替换必须具有相同的长度。

Operation Result Notes
s[i:j] = t slice of s from i to j is replaced by the contents of the iterable t
s[i:j:k] = t the elements of s[i:j:k] are replaced by those of t (1) t must have the same length as the slice it is replacing.

那里也记录了正确的方法。

Operation Result Notes
del s[i:j] same as s[i:j] = []
del s[i:j:k] removes the elements of s[i:j:k] from the list

代码:

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[::2]
print(numbers)

输出:

[1, 3, 5, 7, 9]

【讨论】:

    【解决方案2】:

    numbers[::2] = [] 不需要每隔一个元素就删除一次,因为您已经可以通过编写 numbers[:] = numbers[1::2] 来做到这一点。相反,如果您想(例如)用值 1 替换每个第二个元素,您可以编写以下内容之一,这些内容明确说明了它们的行为。

    for i in range(0, len(numbers), 2):
        numbers[i] = 1
    
    # or:
    numbers[::2] = [1] * len(numbers[::2])
    

    m != n 时,将m 元素分配给n 列表位置的非连续切片的正确行为并不明显。在 cmets 中,您提出了一种可能的行为,但您的建议与切片分配在其他情况下的工作方式不一致(通常,右侧的每个元素在左侧使用一次 ) 并且肯定不满足principle of least astonishment。在这种情况下,我认为大多数人都期望有 no(非引发)行为,因此引发错误是最好的选择。

    【讨论】:

    • 我仍然没有看到提议的扩展切片分配与当前切片分配行为有何不同。例如,numbers[3:5] = [0,0,0,0] 目前提供[0,1,2,0,0,0,0,5,6,7,8,9],所以对我来说,numbers[::2] = [0,0,0,0] 提供[0,0,0,0,1,0,0,0,0,3,0,0,0,0,5,0,0,0,0,7,0,0,0,0,9] 似乎是一致的。
    • @tdy 在numbers[3:5] = [a,b,c,d] 中,abcd 中的每一个在右侧列表中出现一次,之后在左侧列表中出现一次那作业。正常切片分配不能重复值。
    • 啊好的,我现在明白了
    • @tdy 还要考虑numbers[::2] = [5, 6, 7, 8] 的情况,与其他长度的列表相比,它对长度为 7 和 8 的列表会做不同的事情。
    【解决方案3】:

    您必须使用其他答案中已经提到的切片创建一个新列表:

    numbers = numbers[1::2]
    

    如果您在同一个列表上工作,则会导致严重的性能损失,因为向列表中插入或删除(而不是追加!)元素是 O(N)。由于每次插入都有 O(N) 并且有 N/2 次插入,因此总成本为 O(N**2)。你真的不想要那个成本。 另一方面,使用切片的输出创建一个新列表的总成本仅为 O(N)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-11
      • 2021-11-08
      • 1970-01-01
      • 2019-02-05
      • 1970-01-01
      • 2022-09-24
      相关资源
      最近更新 更多