2017-08-17 32 views
1

私はリストとして入力し、元のリストから隣接する要素のタプル(またはサブリスト)を含む別のリストを作成し、終了要素。入力/出力は次のようになります。Pythonの別のリストの隣接する要素のリストを作成します

l_in = [0, 1, 2, 3] 
l_out = [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)] 

私の質問は密接に別題しgetting successive adjacent elements of a listに関連しているが、この他の質問は終わり要素の折り返しを考慮に入れると、要素だけではなく、トリプレットのペアを処理しません。 。私はおそらくよりエレガント(および/または効率的な)を使用して、これを実行する方法があるように感じる、

from collections import deque 
l_in = [0, 1, 2, 3] 
deq = deque(l_in) 
deq.rotate(1) 
deq_prev = deque(deq) 
deq.rotate(-2) 
deq_next = deque(deq) 
deq.rotate(1) 
l_out = list(zip(deq_prev, deq, deq_next)) 
# l_out is [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)] 

をしかし:

私はdequeのを回転させ、それらを一緒にビュン関与するこれを行うには、やや長いアプローチを持っています他の組み込みのPythonの機能たとえば、の機能が dequeの場合、回転リストを所定の位置に変更する代わりに返した場合、これは1本または2本のライナーになる可能性があります(回転リストを一緒に圧縮するこのアプローチはおそらく最も効率的ではありません)。これをよりエレガントに、かつ/または効率的に達成するにはどうすればよいですか?

答えて

0

私は質問を書いていたときより良い解決策を見つけましたが、すでにそれを書いているので、ここに行きます。このソリューションは、少なくともはるかに簡潔である:

l_out = list(zip(l_in[-1:] + l_in[:-1], l_in, l_in[1:] + l_in[:1])) 

はPythonでリストを回転させる方法についての異なった答えのためのthis postを参照してください。スライスはdequeの回転コピーよりも高価であってはならないので、上記

一行溶液は、(私の理解に基づいて)当該溶液と少なくとも同程度に効率的であるべきである(https://wiki.python.org/moin/TimeComplexity参照) 。

さらに効率的な(またはエレガントな)ソリューションの回答はまだまだあります。

1

これは、スライスを行うことができます。

まあ
l_in = [0, 1, 2, 3] 

l_in = [l_in[-1]] + l_in + [l_in[0]] 
l_out = [l_in[i:i+3] for i in range(len(l_in)-2)] 

、またはそのような倒錯:

div = len(l_in) 
n = 3 
l_out = [l_in[i % div: i % div + 3] 
     if len(l_in[i % div: i % div + 3]) == 3 
     else l_in[i % div: i % div + 3] + l_in[:3 - len(l_in[i % div: i % div + 3])] 
     for i in range(3, len(l_in) + 3 * n + 2)] 

あなたは反復回数を指定することができます。

0

リスト回転スライスベースのイディオムlst[i:] + lst[:i]

は、隣接する要素の数の変数nを取っ理解の内側にそれを使用している見られるようなので、すべてがパラメータ化することができ[lst[i:] + lst[:i] for i in range(n)]

より一般的でありたかったです、隣接する要素の数が循環回転しており、 '012' '' '0' 'の添え字インデックスではない場合は開始点であるが-1に設定されているため、巡回回転のnと' phase 'pの開始点は

tst = list(range(4)) 

def rot(lst, n, p=-1): 
    return list(zip(*([lst[i+p:] + lst[:i+p] for i in range(n)]))) 

rot(tst, 3) 
Out[2]: [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)]  

コメントの通りshortendコードを示す

+0

more-itertools簡単に介してインストール、別のライブラリです。 'list(zip(* range [n)]))'のzip(* [lst [i + p:] + lst [:i + p])に返されるものを単純化することができます。 – Grayscale

+0

'n> len(lst)'のように 'n 'を指定すると、最初の要素が各タプルの末尾にある充填値として使用されるという予期しない振る舞いのように思えます(最後の'あなたが見せている腐敗(txt、6、0) 'を繰り返します。 – Grayscale

1

一つのアプローチはmore_itertools.windowed組み合わせるitertoolsを使用することができる:ここ

import itertools as it 

import more_itertools as mit 


l_in = [0, 1, 2, 3] 
n = len(l_in) 
list(it.islice(mit.windowed(it.cycle(l_in), 3), n-1, 2*n-1)) 
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)] 

我々は sliding windowsの無限サイクルを生成し、所望のサブセットをスライスしました。


FWIW、ここで例えば任意の反復可能な入力を与えられた一般的な、柔軟なソリューションのための後者のコードの抽象化ですrange(5)"abcde"iter([0, 1, 2, 3])等:

def get_windows(iterable, size=3, offset=-1): 
    """Return an iterable of windows including an optional offset.""" 
    it1, it2 = it.tee(iterable) 
    n = mit.ilen(it1) 
    return it.islice(mit.windowed(it.cycle(it2), size), n+offset, 2*n+offset) 


list(get_windows(l_in)) 
# [(3, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, 0)] 

list(get_windows("abc", size=2)) 
# [('c', 'a'), ('a', 'b'), ('b', 'c')] 

list(get_windows(range(5), size=2, offset=-2)) 
# [(3, 4), (4, 0), (0, 1), (1, 2), (2, 3)] 

注:私は外側のリスト内包が冗長だと思う

> pip install more_itertools 
+0

'more_itertools.windowed'の使用は、この種の問題のために作られたこれを行うための素晴らしい代替方法のようです。ただし、 'more_itertools'パッケージは組み込みではありません(ただし、' pip3 install more-itertools'で簡単にインストールできます)。 – Grayscale

+0

これは実際には 'list(mit.windowed(l_in [-1:] + l_in + l_in [:1]、3))'に単純化できると思います。これはおそらく私が見たことの中で最もクリーンな方法です遠い – Grayscale

+0

更新されました。ありがとうございました。はい、ウィンドウイングは確かに便利なコンセプトです。あなたは、あなたが望むあらゆるテクニックを適用することを歓迎します。あなたの提案は簡潔ではっきりしており、この場合は確かに動作しますが、リスト(またはタプル)を連結することに依存しています。私は任意のサイズのiterableとウィンドウで動作するはずの一般的な解決策を提供しようとしました。例えば、あなたの提案は、 'range(5)'、ウィンドウサイズ2に対して予期しない答えを与える可能性があります。 – pylang

関連する問題