3

例としてリストを見てみましょう:

a = [255, 255, 1, 255, 255, 255, 1, 2, 255, 255, 2, 255, 255, 3, 255, 3, 255, 255, 255]

255その中の特別な値です。プレースホルダーです。

リスト内のプレースホルダーの一部を置き換えるジェネレーターを作成しました。期待どおりに動作します。

しかし、最初のプレースホルダー[255, 255と最後のプレースホルダーを処理255, 255, 255]してそのまま生成する必要はありません。

そこで、ジェネレーターを修正して解決しようとしました。

パイソン 2.7

from __future__ import print_function
from  itertools import tee, izip, ifilterfalse

def replace(iterable,placeholder=255):
    it = enumerate(iterable) #the position is needed for the logic for the middle of the list
    it = ifilterfalse(lambda x: x[1]==placeholder, it) #create an iterator that deletes all the placeholders
    for i,(left,right) in enumerate(window(it,2)): #Slide through the filtered list with the window of 2 elements
        if i==0: #Leaving the beginning placeholders intact
            for j in range(left[0]):
                yield placeholder

        #SOME LOGIC FOR THE MIDDLE OF THE LIST (it works well)

    #Need to leave the trailing placeholders intact.

コードの理解を容易にするためだけにリストに変換された中間値:

>>>iterable
[255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3,255,255]

>>>it = enumerate(iterable)
[(0, 255), (1, 1), (2, 255), (3, 255), (4, 1), (5, 255), (6, 255), (7, 255), (8, 2), (9, 2), (10, 255), (11, 255), (12, 255), (13, 2), (14, 2), (15, 3), (16, 255), (17, 255), (18, 255), (19, 3), (20, 255), (21, 255)]

>>>it = ifilterfalse(lambda x: x[1]==placeholder, it)
[(1, 1), (4, 1), (8, 2), (9, 2), (13, 2), (14, 2), (15, 3), (19, 3)]

>>>list(enumerate(window(it,2)))
[(0, ((1, 1), (4, 1))), (1, ((4, 1), (8, 2))), (2, ((8, 2), (9, 2))), (3, ((9, 2), (13, 2))), (4, ((13, 2), (14, 2))), (5, ((14, 2), (15, 3))), (6, ((15, 3), (19, 3)))]

したがって、ご覧のとおりlist(enumerate(window(it,2)))、先頭の非プレースホルダー値のインデックスが含まれて(0, ((**1**, 1), (4, 1))),いますが、最初のイテレータが持っていた末尾のプレースホルダーの数に関する情報は含まれていません。最後の非プレースホルダーのインデックスのみを持つlist(enumerate(window(it,2)))この値で終わります。(6, ((15, 3), (**19**, 3)))プレースホルダー値。プレースホルダーがいくつ残っているかはわかりません。

it = enumerate(iterable)によって最初に生成された値に保持される初期イテレータ値の位置を生成することに依存して、主要なプレースホルダーを処理することができましたifilterfalse

しかし、末尾のプレースホルダーを使用して同じことを行う方法を見つけるのにかなりの時間を費やしました。問題はifilterfalse、 の最後のプレースホルダー値を飲み込むだけでenumerate(iterable)あり、それらにアクセスする方法がわかりません (最初に生成された の値ifilterfalseに の値のインデックスが含まれていたため、主要なプレースホルダーが可能でしたenumerate(iterable))。

質問

末尾のプレースホルダーを処理するためにこのコードを修正する最良の方法は何ですか?

どうしてもコードを作ることが目的ではないので(の手法で作ったことあります)、完全に書き直すのではなく、コードを少しいじって解決したいと思います。

実際の作業というよりはトレーニングです。

追加情報

windowここからのコードです。

私のコードは、@nye17 によるこの回答とほぼ同じです。しかし、このコードでは、作成者が最初のリストをインプレースで変更しています。そして、そのコードの結果のリストと同じ値を生成するジェネレーターを作成したいと考えています。

さらに、ジェネレーターがリストだけでなく、イテラブルをパラメーターとして受け入れるようにします (たとえば、ファイルから値を 1 つずつ読み取るイテレーターを受け入れる場合があります)。パラメータとしてリストのみを使用すると、リストを最後からスキャンできるため、タスクが簡単になります。

これは、私が人生で解決しなければならない本当の課題ではありません。あくまで研修用です。

完全なコード http://codepad.org/9UJ9comY

4

3 に答える 3

2
def replace(it, process, placeholder):
    it = iter(it)
    while True:
        item = it.next()
        if item == placeholder:
            yield item
        else:
            yield process(item)
    pcount = 0
    try:
        while True:
            item = it.next()
            if item == placeholder:
                pcount += 1
            else:
                for i in range(pcount):
                    yield process(placeholder)
                pcount = 0
                yield process(item)
    except StopIteration:
        for i in range(pcount):
            yield placeholder

次のように使用します。

>>> a = [0, 0, 1, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 3, 0, 3, 0, 0, 0]
>>> [x for x in replace(a, lambda n: n+20, 0)]
[0, 0, 21, 20, 20, 20, 21, 22, 20, 20, 22, 20, 20, 23, 20, 23, 0, 0, 0]
于 2011-10-13T14:26:50.150 に答える
0

私が思いついた最も簡単な解決策はit = enumerate(iterable)、最後に返された値を保存するジェネレーターをもう 1 つ処理することです。

そのため、次のコードを後it = enumerate(iterable)(replace関数内)に追加しました。

def save_last(iterable):
        for i in iterable:
            yield i
        replace.last_index = i[0] #Save the last value
it = save_last(it)

が使い果たされた後iterable、ジェネレーターの最後の演算子は、生成された値のインデックスを属性として保存します (これはi[0]、tupleenumerateの位置に格納されます) (関数はクラスのインスタンスであり、ローカル変数を持つことができるため)。0replacereplace

it、新しく作成されたジェネレーターにラップされsave_lastます。

関数の最後に、replace.last_index変数に保存されたインデックスを使用するコードを追加しました。

if right[0]<replace.last_index:
    for i in range(replace.last_index-right[0]):
        yield placeholder

完全なコード:

from __future__ import print_function
from  itertools import tee, izip, ifilterfalse


def window(iterable,n):
    els = tee(iterable,n)
    for i,el in enumerate(els):
        for _ in range(i):
            next(el, None)
    return izip(*els)


def replace(iterable,placeholder=255):
    it = enumerate(iterable)

    def save_last(iterable):
        for i in iterable:
            yield i
        replace.last_index = i[0] #Save the last value
    it = save_last(it)

    it = ifilterfalse(lambda x: x[1]==placeholder, it)
    for i,(left,right) in enumerate(window(it,2)):
        if i==0:
            for j in range(left[0]):
                yield placeholder
        yield left[1]
        if right[0]>left[0]+1:
            if left[1]==right[1]:
                for _ in range(right[0]-left[0]-1):
                    yield left[1]
            else:
                for _ in range(right[0]-left[0]-1):
                    yield placeholder
    yield right[1]
    if right[0]<replace.last_index:
        for i in range(replace.last_index-right[0]):
            yield placeholder


a = [255,1,255,255,1,255,255,255,2,2,255,255,255,2,2,3,255,255,255,3,255,255]        
print('\nInput: {}'.format(a))
output = list(replace(a))
print('Proram output: {}'.format(output))
print('Goal output  : {}'.format([255,1,1,1,1,255,255,255,2,2,2,2,2,2,2,3,3,3,3,3,255,255]))

期待どおりに動作します:

Input: [255, 1, 255, 255, 1, 255, 255, 255, 2, 2, 255, 255, 255, 2, 2, 3, 255, 255, 255, 3, 255, 255]
Proram output: [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 255, 255]
Goal output  : [255, 1, 1, 1, 1, 255, 255, 255, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 255, 255]

私が気に入らない唯一のことは、非常に効率的な Cifilterfalsesave_last書かれたものと Python で書かれたものの組み合わせです。

于 2011-10-15T17:50:18.660 に答える
0
def replace(it, placeholder):
    while True:
        curr = it.next()
        if curr == placeholder:
            yield curr
        else:
            break

    yield curr

    try:
        cache = []
        while True:      
            curr = it.next()

            if curr == placeholder:
                cache.append(curr)
            else:
                for cached in cache:
                    yield TRANSFORM(cached)
                yield curr
                cache = []

    except StopIteration:
        for cached in cache:
            yield cache
于 2011-10-13T18:56:42.323 に答える