2017-10-31 7 views
5

私はこのサイトのリストの要素を交換してみましたが、ほとんどの場合、ある要素を別の要素と入れ替えることができます。違うリストスライスを交換するためのエレガントな方法?

ここでは、不等長のスライスの位置を入れ替えようとしています。例のリストについて:

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] 

当然のことながら、それは動作しません、それはx[5:7]とスワップx[0:4]

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

別の例:最初の2つの要素を入れ替え

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

私はそれはスワッピングがslice1の最初の要素がslice2の最初の要素の前の位置を占めているようなものであることは明らかです願っています。残りは次のとおりです。

これを簡単かつ効率的に行う方法はありますか?

+0

でそれを試してみてください、その '__set_item__'メソッドは以前のスライスの割り当てを追跡し、次のスライスのインデックスを再マップします。これを効率的にする。 O(logN)w.r.t.割り当ての数---索引変換を追跡するための重要でないデータ構造が必要です。 – nickie

答えて

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] 
+1

私の読書の質問は、さまざまなサイズの任意のスライスを交換することです。ローテーションは単なる(簡単な)サブケースです。 – nickie

+0

しかし、これは2番目のケースではうまくいかないでしょうか?最後の値の位置は維持されますが、最初の3つの要素と交換される前の2つの要素が保持されます。 @ニッキーはそれを正しく言っています –

0

簡単な方法は、ストレート、スライスの連結である:

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

print x 

出力:

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

2番目のケースでは、同様に3つにスライスします。ポストされた故障の


分析:

あなたの割り当て試行が間違った形式は次のとおりです。複数の割り当てはない値のストリームとして、式と式が行われます。あなたが個別にこれらの操作を行う場合は、割り当てがそれぞれの場合の小さなスライスに制限されていることがわかりますあなたはパラレル評価まで休憩に入り、

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

の割り当て。

+0

あなたは5を仲間にしていません – citizen2077

+0

これは新しいリストを生成します。質問(私の読書では、もう一度)は、現場での代替に関するものです。 – nickie

+0

これは2番目の例で失敗します –

0

エレガントで完全に一般的な方法はありません。ここではそれほどエレガントな方法があります:

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] 
0

私は、これは十分なはずだと思う:

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] 
関連する問題