4

次のような値があるとします。

n = 5

そして、その階乗を返す関数は次のようになります。

factorial(5)

複数の値をどのように処理しますか:

nums = [1,2,3,4,5]
factorial (nums)

したがって、これらすべての値の階乗をリストとして返しますか?

2つのメソッドを記述せずに、これを処理する最もクリーンな方法は何ですか?Pythonには、このような状況を処理するための良い方法がありますか?

4

6 に答える 6

13
def Factorial(arg):
    try:
        it = iter(arg)
    except TypeError:
        pass
    else:
        return [Factorial(x) for x in it]
    return math.factorial(arg)

繰り返し可能な場合は、繰り返し適用します。それ以外の場合は、通常どおり続行します。

returnまたは、最後をexceptブロックに移動することもできます。

Factorialの本体が決して上昇しないことが確実な場合は、次のTypeErrorように簡略化できます。

def Factorial(arg):
    try:
        return [Factorial(x) for x in arg]
    except TypeError:
        return math.factorial(arg)
于 2009-03-09T21:56:19.050 に答える
9

リスト内包表記

[fac(n) for n in nums]

編集:

申し訳ありませんが、誤解しました。シーケンスと単一の値の両方を処理するメソッドが必要ですか?なぜ2つの方法でこれを行わないのか想像できません。

def factorial(n):
    # implement factorial here
    return answer

def factorial_list(nums):
    return [factorial(n) for n in nums]

別の方法は、ある種の型チェックを行うことです。これは、非常にやむを得ない理由がない限り、避ける方がよいでしょう。

編集2:

MizardXの答えはより良いです、それに投票してください。乾杯。

于 2009-03-09T21:53:08.573 に答える
7

これは時々行われます。

def factorial( *args ):
    def fact( n ):
        if n == 0: return 1
        return n*fact(n-1)
    return [ fact(a) for a in args ]

これは、単純な値とシーケンスで機能するほとんど魔法のような機能を提供します。

>>> factorial(5)
[120]
>>> factorial( 5, 6, 7 )
[120, 720, 5040]
>>> factorial( *[5, 6, 7] )
[120, 720, 5040]
于 2009-03-09T22:20:37.260 に答える
6

Pythonがメソッドのオーバーロードを実行できるかどうかを尋ねている場合:いいえ。したがって、そのようなマルチメソッドを実行することは、メソッドを定義するためのかなり非Python的な方法です。また、命名規則は通常、大文字のクラス名と小文字の関数/メソッドです。

とにかく先に進みたい場合、最も簡単な方法は、ブランチを作成することです。

def Factorial(arg):
  if getattr(arg, '__iter__', False): # checks if arg is iterable
    return [Factorial(x) for x in arg]
  else:
    # ...

または、空想を感じている場合は、任意の機能に対してこれを行うデコレータを作成できます。

def autoMap(f):
    def mapped(arg):
        if getattr(arg, '__iter__', False):
            return [mapped(x) for x in arg]
        else:
            return f(arg)
    return mapped

@autoMap
def fact(x):
    if x == 1 or x == 0:
        return 1
    else:
        return fact(x-1) + fact(x-2)

>>> fact(3)
3
>>> fact(4)
5
>>> fact(5)
8
>>> fact(6)
13
>>> fact([3,4,5,6])
[3, 5, 8, 13]

よりPythonの方法は、可変引数長を使用することですが、次のようになります。

def autoMap2(f):
    def mapped(*arg):
        if len(arg) != 1:
            return [f(x) for x in arg]
        else:
            return f(arg[0])
    return mapped

@autoMap2
def fact(n):
# ...

>>> fact(3,4,5,6)
[3, 5, 8, 13]

2つをまとめてディープマッピングデコレータに入れます。

def autoDeepMap(f):
    def mapped(*args):
        if len(args) != 1:
            return [mapped(x) for x in args]
        elif getattr(args[0], '__iter__', False):
            return [mapped(x) for x in args[0]]
        else:
            return f(args[0])
    return mapped

@autoDeepMap
def fact(n):
# ...

>>> fact(0)
1
>>> fact(0,1,2,3,4,5,6)
[1, 1, 2, 3, 5, 8, 13]
>>> fact([0,1,2,3,4,5,6])
[1, 1, 2, 3, 5, 8, 13]
>>> fact([0,1,2],[3,4,5,6])
[[1, 1, 2], [3, 5, 8, 13]]
>>> fact([0,1,2],[3,(4,5),6])
[[1, 1, 2], [3, [5, 8], 13]]
于 2009-03-09T21:54:11.363 に答える
3

NumPy/SciPy のvectorizeをご覧になることをお勧めします。

numpy の世界では、単一の int-arg 階乗関数が与えられた場合、次のようなことを行います

  vFactorial=np.vectorize(Factorial)
  vFactorial([1,2,3,4,5])
  vFactorial(6)

ただし、最後のケースでは、生の int ではなく、単一要素の numpy 配列が返されることに注意してください。

于 2009-03-09T22:39:54.483 に答える
3

または、リスト内包表記の構文が気に入らず、新しいメソッドをスキップしたい場合:

def factorial(num):
    if num == 0:
        return 1
    elif num > 0:
        return num * factorial(num - 1)
    else:
        raise Exception("Negative num has no factorial.")

nums = [1, 2, 3, 4, 5]
# [1, 2, 3, 4, 5]

map(factorial, nums)
# [1, 2, 6, 24, 120, 720]
于 2009-03-09T22:22:41.030 に答える