2

ほんの少しの背景:ユーザーがスケルトンテキスト、2つの数字(下限と上限)、および単語のリストを入力するプログラムを作成しています。出力は、スケルトンテキストに対する一連の変更です。

サンプル入力:

text = "Player # likes @." (replace # with inputted integers and @ with words in list)
lower = 1
upper = 3
list = "apples, bananas, oranges"

ユーザーは、最初に数値を繰り返すことを選択できます。

Player 1 likes apples.
Player 2 likes apples.
Player 3 likes apples.

または最初の言葉:

Player 1 likes apples.
Player 1 likes bananas.
Player 1 likes oranges.

数字キー(ユーザーが入力した整数)または単語キー(入力リストの単語から)に基づいて異なるタイプの辞書を作成し、後で辞書の値を反復処理することで、これら2つの出力方法を分割することにしました。

辞書の作成には次の2種類があります。

def numkey(dict): # {1: ['Player 1 likes apples', 'Player 1 likes...' ] }

    text, lower, upper, list = input_sort(dict)
    d = {}

    for num in range(lower,upper+1):
        l = []
        for i in list:
            l.append(text.replace('#', str(num)).replace('@', i))
        d[num] = l
    return d

def wordkey(dict): # {'apples': ['Player 1 likes apples', 'Player 2 likes apples'..] }

    text, lower, upper, list = input_sort(dict)
    d = {}

    for i in list:
        l = []
        for num in range(lower,upper+1):
            l.append(text.replace('#', str(num)).replace('@', i))
        d[i] = l
    return d

異なるタイプの辞書を作成するための2つの別個の関数があることは問題ありませんが、2つの間に多くの繰り返しが見られます。1つの辞書関数を作成し、それに異なる値を渡して、ネストされたforループの順序を変更し、探している特定の{key:value}ペアを作成する方法はありますか?

これがどのように行われるのかわかりません。これに役立つ可能性のある関数型プログラミングやその他のパラダイムに関連するものはありますか?質問は少し抽象的で、何よりもスタイル/デザイン指向です。

4

3 に答える 3

2

出力を生成するために辞書は必要ありません。次のようなものを使用できます。

import itertools

numbers = range(lower, upper + 1)
words = "a, b, c".split(", ")

data = (numbers, words) if numbers_first else (words, numbers)
for n, w in itertools.product(*data):
    if not numbers_first: n, w = w, n
    print("Player %d likes %s." % (n, w))

ループの内側を避けるためにif、フォーマット文字列を動的に生成できます。例:

template = "Player # likes @."
subs = ("{n}", "{w}") if numbers_first else ("{w}", "{n}")
format = make_format(template, subs) # escape {}, replace # and @

# ...
for n, w in product(*data):
    print(format.format(n=n, w=w))
于 2012-06-03T17:00:44.860 に答える
1

この場合、2つのプロセスを1つの関数に強制するのではなく、各関数をはるかに短くすると思います。

def numkey(dict):
    text, lower, upper, list = input_sort(dict)
    d = {x: [text.replace('#',str(x)).replace('@',item) 
            for item in list.split(', ')] for x in xrange(lower,upper+1)}
    return d

def wordkey(dict):
    text, lower, upper, list = input_sort(dict)
    d = {item: [text.replace('#',str(x)).replace('@',item) 
            for x in xrange(lower,upper+1)] for item in list.split(', ')}
    return d

理論的には、またはそのようなものを使用してdictの作成をリファクタリングすることもできますがmake_dict(dict, outer, inner)、特にintを何らかの方法で前処理する必要があることを考えると、このような短いコードでは明確ではなくなると思います。

于 2012-06-03T16:55:21.357 に答える
1

より一般的な方法は次のとおりです。

from itertools import product

def generate(skeleton, replacements):
    values = (product([k], v) for k, v in replacements.items())
    for p in product(*values):
        s = skeleton
        for a, b in p:
            s = s.replace(a, str(b))
        yield s

replacements{placeholder: list of values}たとえば、辞書であることが期待されます。

gen = generate("Player # likes @.", {'#': range(1,3), '@': ['apples', 'bananas']})    
for phrase in gen:
    print phrase

プリント

Player 1 likes apples.
Player 2 likes apples.
Player 1 likes bananas.
Player 2 likes bananas.

値の1つを「静的」にする必要がある場合は、単一要素のリストを指定してください。

gen = generate("Player # likes @.", {'#': [1], '@': ['apples', 'bananas']})    

これは任意の数のプレースホルダーで機能することに注意してください。

gen = generate("Player # likes @ and can $", {
    '#': range(1,3), 
    '@': ['apples', 'bananas'],
    '$': ['swim', 'run', 'jump']
})    
于 2012-06-03T18:00:27.873 に答える