【问题标题】:Elegant method for swapping unequal list slices? [duplicate]交换不平等列表切片的优雅方法? [复制]
【发布时间】:2017-10-31 22:56:47
【问题描述】:

我已经研究过在本网站的列表中交换元素,但大多数情况下都是处理一个元素与另一个元素的交换。

在这里,我试图交换不等长切片的位置。示例列表:

x = [6,2,4,3,4,1,4,5]

我希望有一种优雅的方式来交换列表和变量中的值,例如下面的形式:

x[0:1], x[1:7] = x[1:7], x[0:1]

#Expected output
x = [2, 4, 3, 4, 1, 4, 5, 6]

不出所料,它不起作用,它交换了前两个元素:

#Actual output
x = [2, 6, 4, 3, 4, 1, 4, 5]

另一个例子:用x[5:7]交换x[0:4]

#Expected output
x = [1, 4, 4, 6, 2, 4, 3, 5]

我希望很清楚交换是这样的,slice1 的第一个元素占据了slice2 的第一个元素的先前位置。其余的如下。

有没有一种简单的方法可以优雅而高效地做到这一点?

【问题讨论】:

  • 我能看到的支持涉及切片的任意序列分配的唯一“优雅”方法是定义一个包装列表的自定义对象,其__set_item__ 方法将跟踪以前的切片分配并重新映射以下的索引。提高效率——例如O(logN) w.r.t.分配的数量 --- 将需要一个重要的数据结构来跟踪索引转换。

标签: python python-3.x list


【解决方案1】:

您可以使用collections.deque 来旋转值:

import collections
x = [6,2,4,3,4,1,4,5]
d = collections.deque(x)
d.rotate(-1)
print(d)

输出:

[2, 4, 3, 4, 1, 4, 5, 6]

【讨论】:

  • 这个问题(在我的阅读中)是关于交换不同大小的任意切片。旋转只是一个(简单的)子案例。
  • 但这不适用于第二种情况,对吧?保留最后一个值位置,但它之前的两个元素与前 3 个元素交换。 @nickie 说得对
【解决方案2】:

仅使用列表的直接方法是使用直接切片连接:

x = [6,2,4,3,4,1,4,5]
x = x[1:] + x[:1]  

print x

输出:

[2, 4, 3, 4, 1, 4, 5, 6]

对于第二种情况,您将其切成三段。


发布失败分析:

您尝试的赋值形式错误:多次赋值是在表达式之间完成的,而不是作为值流。您输入的内容分解为并行评估和分配

x[0:1] = x[1:7]
x[1:7] = x[0:1]

如果您单独执行这些操作,您会发现在每种情况下分配都仅限于较小的切片。

【讨论】:

  • 你少了一个 5 位队友
  • 这会生成一个新列表。这个问题(在我的阅读中,再次)是关于就地替换的。
  • 第二个例子失败了
  • @Yukon:谢谢。我没有注意到边界问题。修复和改进。
【解决方案3】:

我认为没有任何优雅的、完全通用的方式。这是一种不太优雅的方式:

def swapslices(l, from1, to1, from2, to2):
    if not (from1 <= to1 <= from2 <= to2):
        raise ValueError('slices out of order or overlapping')
    if to1 - from1 == to2 - from2:
        # Easy case. No need to shift the part between the two slices.
        l[from1: to1], l[from2, to2] = l[from2: to2], l[from1: to1]
    else:
        # Hard case. We need to rewrite the whole section.
        l[from1: to2] = l[from2: to2] + l[to1: from2] + l[from1: to1]

此函数要求您首先传递较低的切片,并且您不要尝试使用像6:3 这样的切片。

该函数依赖于这样一个事实,即如果您尝试在此处交换切片 ac

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    ----  ----  -------
      a     b       c

这样做相当于用c + b + a 替换整个a + b + c 部分:

[0, 5, 6, 7, 3, 4, 1, 2, 8, 9]
    -------  ----  ----
        c      b     a

例子:

>>> l = list(range(10))
>>> swapslices(l, 1, 3, 5, 8)
>>> l
[0, 5, 6, 7, 3, 4, 1, 2, 8, 9]

【讨论】:

    【解决方案4】:

    我认为这应该足够了:

    def swapslices(lst, from1, to1, from2, to2):
        # assumes from1:to1 < from2:to2
        def reverse(l, r):
           r = r - 1
           while l < r:
               lst[l], lst[r] = lst[r], lst[l]
               l += 1
               r -= 1
        reverse(to1, from2)
        reverse(from2, to2)
        reverse(from1, to1)
        reverse(from1, to2)
    

    尝试一下

    a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    swapslices(a, 2, 4, 6, 9)
    # a is now [0, 1, 6, 7, 8, 4, 5, 2, 3, 9, 10]
    

    【讨论】:

      猜你喜欢
      • 2012-11-25
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 2012-11-17
      • 2019-01-29
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      相关资源
      最近更新 更多