101

オブジェクトのリストを繰り返し処理して、前のアイテム、現在のアイテム、次のアイテムにアクセスするにはどうすればよいですか?このC/C ++コードのように、Pythonで?

foo = somevalue;
previous = next = 0;

for (i=1; i<objects.length(); i++) {
    if (objects[i]==foo) {
        previous = objects[i-1];
        next = objects[i+1];
    }
}
4

15 に答える 15

164

これまでのソリューションはリストのみを扱い、ほとんどはリストをコピーしていました。私の経験では、それは不可能な場合が多いです。

また、リスト内で要素を繰り返すことができるという事実を扱いません。

質問のタイトルには「ループ内の前と次の値」と書かれていますが、ここでほとんどの回答をループ内で実行すると、各要素でリスト全体を繰り返し処理して見つけることになります。

だから私は関数を作成しました。モジュールを使用してitertools、イテラブルを分割およびスライスし、前の要素と次の要素を一緒にしてタプルを生成します。あなたのコードが何をするかは正確ではありませんが、おそらくあなたの問題を解決できるので、一見の価値があります。

from itertools import tee, islice, chain, izip

def previous_and_next(some_iterable):
    prevs, items, nexts = tee(some_iterable, 3)
    prevs = chain([None], prevs)
    nexts = chain(islice(nexts, 1, None), [None])
    return izip(prevs, items, nexts)

次に、ループで使用すると、前と次のアイテムが含まれます。

mylist = ['banana', 'orange', 'apple', 'kiwi', 'tomato']

for previous, item, nxt in previous_and_next(mylist):
    print "Item is now", item, "next is", nxt, "previous is", previous

結果:

Item is now banana next is orange previous is None
Item is now orange next is apple previous is banana
Item is now apple next is kiwi previous is orange
Item is now kiwi next is tomato previous is apple
Item is now tomato next is None previous is kiwi

これは、任意のサイズ リスト (リストをコピーしないため) と、任意のイテラブル (ファイル、セットなど) で動作します。このようにして、シーケンスを反復するだけで、ループ内で前と次のアイテムを使用できるようになります。シーケンス内のアイテムを再度検索する必要はありません。

コードの簡単な説明:

  • tee入力シーケンスに対して 3 つの独立した反復子を効率的に作成するために使用されます
  • chain2 つのシーケンスを 1 つにリンクします。ここでは、単一要素のシーケンス[None]を追加するために使用されますprevs
  • islice最初の要素を除くすべての要素のシーケンスを作成するために使用され、最後に a をchain追加するために使用されますNone
  • some_iterable次のような 3 つの独立したシーケンスがあります。
    • prevs:None, A, B, C, D, E
    • items:A, B, C, D, E
    • nexts:B, C, D, E, None
  • finallyizipは、3 つのシーケンスをトリプレットの 1 つのシーケンスに変更するために使用されます。

izip入力シーケンスが使い果たされると停止することに注意してください。そのため、 の最後の要素はprevs無視されます。これは正しいです。最後の要素がその になるような要素はありませんprev。から最後の要素を取り除こうとすることもできますprevsが、izipの動作により冗長になります

teeまた、 、izipisliceおよびがモジュールにchain由来することにも注意してください。itertools入力シーケンスをその場で (遅延して) 操作するため、効率的になり、いつでも一度にシーケンス全体をメモリに保持する必要がなくなります。

ではpython 3、インポート中にエラーが表示されますが、代わりに をizip使用できます。インポートする必要はありません。 ソースで事前定義されていますzipizipzippython 3

于 2009-06-18T11:12:58.690 に答える
121

これでうまくいくはずです。

foo = somevalue
previous = next_ = None
l = len(objects)
for index, obj in enumerate(objects):
    if obj == foo:
        if index > 0:
            previous = objects[index - 1]
        if index < (l - 1):
            next_ = objects[index + 1]

これが関数に関するドキュメントenumerateです。

于 2009-06-18T10:28:51.383 に答える
7

リスト内包表記を使用して、現在、前、次の要素を持つ 3 タプルを返します。

three_tuple = [(current, 
                my_list[idx - 1] if idx >= 1 else None, 
                my_list[idx + 1] if idx < len(my_list) - 1 else None) for idx, current in enumerate(my_list)]
于 2015-09-22T10:40:53.257 に答える
4

境界エラーのないジェネレーターを使用したバージョンを次に示します。

def trios(iterable):
    it = iter(iterable)
    try:
        prev, current = next(it), next(it)
    except StopIteration:
        return
    for next in it:
        yield prev, current, next
        prev, current = current, next

def find_prev_next(objects, foo):
    prev, next = 0, 0
    for temp_prev, current, temp_next in trios(objects):
        if current == foo:
            prev, next = temp_prev, temp_next
    return prev, next

print(find_prev_next(range(10), 1))
print(find_prev_next(range(10), 0))
print(find_prev_next(range(10), 10))
print(find_prev_next(range(0), 10))
print(find_prev_next(range(1), 10))
print(find_prev_next(range(2), 10))

コードとは異なり、最初または最後の要素で「foo」を検索しないという境界の動作に注意してください。繰り返しますが、境界セマンティクスは奇妙です...そしてあなたのコードから推測するのは難しいです:)

于 2009-06-18T11:29:11.137 に答える
2

Python >= 2.5 の簡潔さのために条件式を使用する

def prenext(l,v) : 
   i=l.index(v)
   return l[i-1] if i>0 else None,l[i+1] if i<len(l)-1 else None


# example
x=range(10)
prenext(x,3)
>>> (2,4)
prenext(x,0)
>>> (None,2)
prenext(x,9)
>>> (8,None)
于 2009-06-18T11:02:48.973 に答える
0

indexリストで使用して場所を見つけ、somevalue必要に応じて前と次を取得できます。


def find_prev_next(elem, elements):
    previous, next = None, None
    index = elements.index(elem)
    if index > 0:
        previous = elements[index -1]
    if index < (len(elements)-1):
        next = elements[index +1]
    return previous, next


foo = 'three'
list = ['one','two','three', 'four', 'five']

previous, next = find_prev_next(foo, list)

print previous # should print 'two'
print next # should print 'four'


于 2009-06-18T10:49:16.413 に答える
-1

Pythonic でエレガントな方法:

objects = [1, 2, 3, 4, 5]
value = 3
if value in objects:
   index = objects.index(value)
   previous_value = objects[index-1]
   next_value = objects[index+1] if index + 1 < len(objects) else None
于 2015-10-09T11:06:07.620 に答える