1行の頭と尾


90

最初の要素のリストと「テール」を単一のコマンドでアンパックするpythonicの方法はありますか?

例えば:

>> head, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

9
リストはPythonの単一リンクリストとして実装されていないため、この操作にはコストがかかります(リスト全体をコピーする必要があるなど)。何を達成したいかによって、これが問題になる場合とそうでない場合があります。このタイプのリスト分解は関数型言語でよく見られるため、実際には非常に安価な操作であるため、私はそれについて言及しているだけです。
Niklas B.

回答:


189

Python 3.xでは、これをうまく行うことができます:

>>> head, *tail = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

3.xの新機能は*、アンパックで演算子を使用して、追加の値を意味することです。PEP 3132-Extended Iterable Unpackingで説明されています。これには、シーケンスだけでなく、イテラブルを処理できるという利点もあります。

それも本当に読みやすいです。

PEPで説明されているように、(一時的なリストを作成することなく)2.xで同等の操作を行う場合は、次のようにする必要があります。

it = iter(iterable)
head, tail = next(it), list(it)

コメントで述べたように、これheadは例外をスローするのではなく、のデフォルト値を取得する機会も提供します。この動作がnext()必要な場合は、オプションの2番目の引数にデフォルト値を指定します。これnext(it, None)によりNone、head要素がない場合に表示されます。

当然、リストで作業している場合、3.x構文を使用しない最も簡単な方法は次のとおりです。

head, tail = seq[0], seq[1:]

1
申し訳ありませんが、私はテールという用語を不適切に使用しました。私が例で言っていること、つまり、最初の要素のないリストです
Giacomo d'Antonio

1
@NikolayFominyhどちらも同じです。どちらもhead要素を受け取り、tail要素を含む新しいリストを作成します。複雑さの違いはありません。別のクラスは__getitem__/ __setitem__を実装して末尾操作を遅延実行できますが、組み込みリストはそうではありません。
Gareth Latty 2017

2
100万回実行する800要素のリストでは、headに2.8秒、* tail = seq解、headに1.8秒、tail = seq [0]、seq [1:]解があります。リストのスライスはさらに高速です。
カブ2017年

2
@CMCDragonkaiいいえ、Pythonのメインリストクラスは配列リストです。これは、テールを新しいリストにコピーすることを伴うため、O(n)になります(ヘッドに対して1つのO(1)を取得)。
Gareth Latty、2018年

1
このすばらしい構文は、python 3.x
次に

36
>>> mylist = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> head, tail = mylist[0], mylist[1:]
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

9

ただし、O(1)のhead,tail操作の複雑さについては、使用する必要がありますdeque

次の方法:

from collections import deque
l = deque([1,2,3,4,5,6,7,8,9])
head, tail = l.popleft(), l

リストのすべての要素を反復処理する必要がある場合に役立ちます。たとえば、単純なマージでは、2つのパーティションをマージソートでマージします。


deque(list_instance)はO(N)の複雑さを持っているようです。私が間違っている?
НикитаКонин

1
@НикитаКонин、あなたはdequeの構築について正しいです。ただし、最初の要素に複数回アクセスする場合は、head, tail = l.popleft(), l〜O(1)です。head, tail = seq[0], seq[1:]O(n)です。
Nikolay Fominyh 2017年

それはあなただけで行うことができますように見えるhead = l.popleft()tailのためだけの別名ですl。変更もl変更した場合tail
kon psych

2

Python 2、ラムダを使用

>>> head, tail = (lambda lst: (lst[0], lst[1:]))([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
>>> head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]

1
なぜ世界でこれを行うのではなく、なぜこれを行うのhead, tail = lst[0], lst[1:]ですか?OPがリテラルを使用することを意味する場合、彼は頭と尾を手動で分割できますhead, tail = 1, [1, 2, 3, 5, 8, 13, 21, 34, 55]
Filipe Pina

1
(1)Opの質問は、これを1行で行うことができるかどうかです(lst = ...前の行ではできません)。(2)head, tail = lst[0], lst[1:]実行すると、コードが副作用(オープン状態)にさらされたままになりhead, tail = get_list()[0], get_list()[1:]、Opの形式とは異なりhead, tail = **some_magic applied to** [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]ます。
BobIsNotMyName 2018年

そうは言っても、これは頭/尾を取得するための難読化された悪い方法であることを認めます。しかし、私はそれがOp 2の特定の質問に対するPython 2の最良の答えだと思いました。
BobIsNotMyName 2018年

1

上に構築さ@GarethLattyからのPython 2溶液を、以下では、Python 2の中間変数せずに、単一のライン相当を取得する方法です。

t=iter([1, 1, 2, 3, 5, 8, 13, 21, 34, 55]);h,t = [(h,list(t)) for h in t][0]

例外に対応する必要がある場合(つまり、空のリストをサポートする場合)、次を追加します。

t=iter([]);h,t = ([(h,list(t)) for h in t]+[(None,[])])[0]

セミコロンなしで実行したい場合は、以下を使用します。

h,t = ([(h,list(t)) for t in [iter([1,2,3,4])] for h in t]+[(None,[])])[0]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.