1

一連の「構成」を生成するシステムをセットアップしようとしています。これらの構成は、Pythondictに格納されている単純なキーと値のペアです。

これらの構成は、一連の関数を使用してdictを変換した結果です。これは、私がワークフローと呼んでいるものです。

これが私が最終的に得たものの簡単な例です:

global_data = [dict()]

def workflow_step1(data):
    results = []
    for i in range(1,4):
        data['key'] = i
        results.append(copy.deepcopy(data))
    return results

def workflow_step2(data):
    results = []
    for i in range(1,3):
        data['otherkey'] = i
        results.append(copy.deepcopy(data))
    return results

def workflow_step3(data):
    data['yetanotherkey'] = 42
    return [copy.deepcopy(data)]

def list_workflow():
    return [workflow_step1, workflow_step2, workflow_step3]

def merge(lhs,rhs):
    return lhs+rhs

def run(data):
    for step in list_workflow():
        data = reduce(lambda lhs, rhs: lhs+rhs, [step(d) for d in data])
    return data

print run(global_data)

これはうまく機能します、私は得ます:

[{'yetanotherkey': 42, 'otherkey': 1, 'key': 1},
 {'yetanotherkey': 42, 'otherkey': 2, 'key': 1},
 {'yetanotherkey': 42, 'otherkey': 1, 'key': 2},
 {'yetanotherkey': 42, 'otherkey': 2, 'key': 2},
 {'yetanotherkey': 42, 'otherkey': 1, 'key': 3},
 {'yetanotherkey': 42, 'otherkey': 2, 'key': 3}]

ご覧のとおり、目標はdictのすべての可能な組み合わせを取得することです。ワークフローの各ステップは、可能な組み合わせのセットを返します。これにより、次のステップの可能性の新しいブランチが作成されます。

私が直面している問題は、ユーザーがますます多くのワークフローステップを作成しているため、組み合わせ爆発につながることです。

私の素朴なデザインの問題は、すべての可能性のツリー全体を一度に生成することです。

yield私は、ジェネレーターを使用してこれを解決し、一度に1つの可能性を生成して、すべてを同時に保存しないことを望んでいました。

もちろん、yieldを使用してワークフローステップを書き直すことができました。

def workflow_step1(data):
    for i in range(1,4):
        data['key'] = i
        yield copy.deepcopy(data)

def workflow_step2(data):
    for i in range(1,3):
    data['otherkey'] = i
        yield copy.deepcopy(data)

def workflow_step3(data):
    data['yetanotherkey'] = 42
    yield copy.deepcopy(data)

def list_workflow():
    yield workflow_step1
    yield workflow_step2
    yield workflow_step3

runしかし、各ステップを順番に処理するように関数を書き直す方法を頭の中で考えさせることはできません。私は収量と発電機の頭脳迷路に迷いました。

どんなアイデアでも大歓迎です!

4

3 に答える 3

3

私はitertools.productあなたが望むことを正確に行うと思います。これは、一度に 3 つのステップの 1 つの組み合わせを生成するジェネレーターを返すアプローチです。1 つのステップにさらに多くのオプションがある場合でも、事前に膨大な時間やメモリを消費することはありません。

def step1():
    return [("key", i) for i in range(1,4)]

def step2():
    return [("otherkey", i) for i in range(1,3)]

def step3():
    return [("yetanotherkey", 42)]

def workflow_generator():
    return (dict(p) for p in itertools.product(step1(), step2(), step3()))

可変数のステップを処理できるようにしたい場合は、それを機能させるために少し変更することができます。

def workflow_generator(steps):
    return (dict(p) for p in itertools.product(*(step() for step in steps)))

このバージョンを で呼び出すworkflow_generator([step1, step2, step3])と、以前のバージョンと同じ結果が得られますが、必要に応じて別の方法 (関数など) で引数を組み立てることもできます。

于 2012-11-02T20:35:23.313 に答える
0

はい、データ構造がめちゃくちゃです。次のコードは、アイデアを提供するためのものです (現在の構造に関して完全に機能するわけではありません)。基本的にツリーを使い、ステップを登録するワークフローマネージャーのようなクラスを作るべきです。ステップはステップの木です。数字の代わりに真の ID を使用してください。

2つの提案

1.

import copy

global_data = [dict()]

class workflowManager:

    def __init__(self):
        self.steps = []
        self.data = list()

    def registerStep(self,step,stepNumber=1):
        for i in range(1,stepNumber+1):
            self.steps.append(step)

    def registerSubStep(self,step,substep):


    '''
    def hookToStep(self,step,hook):
        #find all steps
        indices = [i for i, x in enumerate(self.steps) if x == step]
        print 'hooking at ',indices
        for k in indices:
            a = self.steps[:k]
            b = self.steps[k:]
            self.steps = a + [hook] + b
    '''

    def performOnData(self):
        print 'self.data ',self.data
        for step in self.steps:
            print 'performing step ',step
            print 'data ',self.data
            self.data = step(self.data)

    def __str(self):
        return str(data)

def step1(data):
    lastn = 0
    try:
        lastn = data[-1]['key']
    except:
        pass
    data.append({'key': lastn+1})
    return data

def step2(data):
    lastn = 0
    try:
        lastn = data[-1]['otherkey']
    except:
        pass

    data.append({'otherkey': lastn+1})
    return data

def step3(data):
    data.append({'yetanotherkey': 42})
    return data


w = workflowManager()
w.step_register(step1,4)
#w.step_register(step2,3)
#w.step_register(step3,1)
w.hookToStep(step1,step3)

print w

w.performOnData()

print w

2.

class Step:

    def __init__(self,name,extra=None):
        self.steps = []
        self.name = name

    def addChild(self,child,repeat=1):
        for j in range(1,repeat+1):
            self.steps.append(child)

    def __str__(self):
        s = self.name + "\n"
        for sub in self.steps:
            s+=str(sub)
        return s


step1 = Step("yetanotherkey",42) #root
step2 = Step("otherkey")
step3 = Step("key")

step2.addChild(step3,2)
step1.addChild(step2,3)

print step1
于 2012-11-02T20:44:17.553 に答える