web-dev-qa-db-ja.com

Pythonのパスカルの三角形

Pythonの学習経験として、Pascalの三角形の独自のバージョンをコーディングしようとしています。始めたばかりなので数時間かかりましたが、次のコードが出てきました。

pascals_triangle = []

def blank_list_gen(x):
    while len(pascals_triangle) < x:
        pascals_triangle.append([0])

def pascals_tri_gen(rows):
    blank_list_gen(rows)
    for element in range(rows):
        count = 1
        while count < rows - element:
            pascals_triangle[count + element].append(0)
            count += 1
    for row in pascals_triangle:
        row.insert(0, 1)
        row.append(1)
    pascals_triangle.insert(0, [1, 1])
    pascals_triangle.insert(0, [1])

pascals_tri_gen(6)

for row in pascals_triangle:
    print(row)

返す

[1]
[1, 1]
[1, 0, 1]
[1, 0, 0, 1]
[1, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1]

しかし、私はここからどこへ行くのか分かりません。何時間も頭を壁にぶつけていました。私はあなたが私のためにそれをしたくないことを強調したい。正しい方向に私を押してください。リストとして、私のコードは戻ります

[[1], [1, 1], [1, 0, 1], [1, 0, 0, 1], [1, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 1]]

ありがとう。

編集:私はいくつかの良いアドバイスを取り、コードを完全に書き直しましたが、現在別の問題に直面しています。これが私のコードです。

import math

pascals_tri_formula = []

def combination(n, r):
    return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))

def for_test(x, y):
    for y in range(x):
        return combination(x, y)

def pascals_triangle(rows):
    count = 0
    while count <= rows:
        for element in range(count + 1):
            [pascals_tri_formula.append(combination(count, element))]
        count += 1

pascals_triangle(3)

print(pascals_tri_formula)

しかし、出力が少し望ましくないことがわかりました。

[1, 1, 1, 1, 2, 1, 1, 3, 3, 1]

どうすれば修正できますか?

13
louie mcconnell

OKコードレビュー:

import math

# pascals_tri_formula = [] # don't collect in a global variable.

def combination(n, r): # correct calculation of combinations, n choose k
    return int((math.factorial(n)) / ((math.factorial(r)) * math.factorial(n - r)))

def for_test(x, y): # don't see where this is being used...
    for y in range(x):
        return combination(x, y)

def pascals_triangle(rows):
    result = [] # need something to collect our results in
    # count = 0 # avoidable! better to use a for loop, 
    # while count <= rows: # can avoid initializing and incrementing 
    for count in range(rows): # start at 0, up to but not including rows number.
        # this is really where you went wrong:
        row = [] # need a row element to collect the row in
        for element in range(count + 1): 
            # putting this in a list doesn't do anything.
            # [pascals_tri_formula.append(combination(count, element))]
            row.append(combination(count, element))
        result.append(row)
        # count += 1 # avoidable
    return result

# now we can print a result:
for row in pascals_triangle(3):
    print(row)

プリント:

[1]
[1, 1]
[1, 2, 1]

パスカルの三角形の説明:

これは "n choose k" (つまり、n個のアイテムの順序付けられたリストから、いくつの異なる方法(順序を無視)でk個のアイテムを選択できるか)の式です。

from math import factorial

def combination(n, k): 
    """n choose k, returns int"""
    return int((factorial(n)) / ((factorial(k)) * factorial(n - k)))

これがitertools.combinationsに関連するものかどうかを尋ねるコメンター-実際に関連しています。 「n choose k」は、組み合わせから要素のリストの長さを取得することで計算できます。

from itertools import combinations

def pascals_triangle_cell(n, k):
    """n choose k, returns int"""
    result = len(list(combinations(range(n), k)))
    # our result is equal to that returned by the other combination calculation:
    assert result == combination(n, k)
    return result

これを実証してみましょう:

from pprint import pprint

ptc = pascals_triangle_cell

>>> pprint([[ptc(0, 0),], 
            [ptc(1, 0), ptc(1, 1)], 
            [ptc(2, 0), ptc(2, 1), ptc(2, 2)],
            [ptc(3, 0), ptc(3, 1), ptc(3, 2), ptc(3, 3)],
            [ptc(4, 0), ptc(4, 1), ptc(4, 2), ptc(4, 3), ptc(4, 4)]],
           width = 20)
[[1],
 [1, 1],
 [1, 2, 1],
 [1, 3, 3, 1],
 [1, 4, 6, 4, 1]]

ネストされたリスト内包表記で自分自身を繰り返すことを避けることができます:

def pascals_triangle(rows):
    return [[ptc(row, k) for k in range(row + 1)] for row in range(rows)]

>>> pprint(pascals_triangle(15))
[[1],
 [1, 1],
 [1, 2, 1],
 [1, 3, 3, 1],
 [1, 4, 6, 4, 1],
 [1, 5, 10, 10, 5, 1],
 [1, 6, 15, 20, 15, 6, 1],
 [1, 7, 21, 35, 35, 21, 7, 1],
 [1, 8, 28, 56, 70, 56, 28, 8, 1],
 [1, 9, 36, 84, 126, 126, 84, 36, 9, 1],
 [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1],
 [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1],
 [1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1],
 [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1],
 [1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]

再帰的に定義された:

三角形で示された関係を使用して、これを再帰的に定義できます(効率は劣りますが、数学的にはより洗練された定義になります)。

 def choose(n, k): # note no dependencies on any of the prior code
     if k in (0, n):
         return 1
     return choose(n-1, k-1) + choose(n-1, k)

おもしろいことに、各行は前の行のほぼ各要素を毎回2回再計算する必要があるため、各行の実行に徐々に時間がかかることがわかります。

for row in range(40):
    for k in range(row + 1):
        # flush is a Python 3 only argument, you can leave it out,
        # but it lets us see each element print as it finishes calculating
        print(choose(row, k), end=' ', flush=True) 
    print()


1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1
1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1
1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1
1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 ...

Ctrlキーを押しながらCキーを押すと、視聴に飽きたときに終了します。

15
Aaron Hall

あなたが自分で実装したいことは知っていますが、私が説明する最善の方法は実装を見ていくことです。これが私がどのように行うかです。この実装は、Pythonの機能がどのように機能するかについてのかなり完全な知識に依存しているため、おそらくこのコードを自分で使用したくないでしょうが、正しい方向に向けられる可能性があります。

def pascals_triangle(n_rows):
    results = [] # a container to collect the rows
    for _ in range(n_rows): 
        row = [1] # a starter 1 in the row
        if results: # then we're in the second row or beyond
            last_row = results[-1] # reference the previous row
            # this is the complicated part, it relies on the fact that Zip
            # stops at the shortest iterable, so for the second row, we have
            # nothing in this list comprension, but the third row sums 1 and 1
            # and the fourth row sums in pairs. It's a sliding window.
            row.extend([sum(pair) for pair in Zip(last_row, last_row[1:])])
            # finally append the final 1 to the outside
            row.append(1)
        results.append(row) # add the row to the results.
    return results

使用法:

>>> for i in pascals_triangle(6):
...     print(i)
... 
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
10
Aaron Hall

Zipを使用せず、ジェネレーターを使用:

def gen(n,r=[]):
    for x in range(n):
        l = len(r)
        r = [1 if i == 0 or i == l else r[i-1]+r[i] for i in range(l+1)]
        yield r

例:

print(list(gen(15)))

output:

[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1], [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1], [1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1], [1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1], [1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1], [1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1]]

三角形として表示

それを美しい三角形で描くには(n <7でのみ機能し、それを超えると、それは配布されません。refdraw_beautiful for n> 7)

n <7の場合

def draw(n):
    for p in gen(n):
        print(' '.join(map(str,p)).center(n*2)+'\n')

eg:

draw(10

output:

      1       

     1 1      

    1 2 1     

   1 3 3 1    

  1 4 6 4 1   

1 5 10 10 5 1   

任意のサイズ

最大幅を知る必要があるため、ジェネレーターを利用できません

def draw_beautiful(n):
    ps = list(gen(n))
    max = len(' '.join(map(str,ps[-1])))
    for p in ps:
        print(' '.join(map(str,p)).center(max)+'\n')

例(2):任意の数で機能します:

draw_beautiful(100)

example of n = 100

6
MortalViews

私の試みは次のとおりです。

_def generate_Pascal_triangle(rows):
    if rows == 1: return [[1]]

    triangle = [[1], [1, 1]] # pre-populate with the first two rows

    row = [1, 1] # Starts with the second row and calculate the next

    for i in range(2, rows):
        row = [1] + [sum(column) for column in Zip(row[1:], row)] + [1]
        triangle.append(row)

    return triangle

for row in generate_Pascal_triangle(6):
    print row
_

討論

  • 三角形の最初の2行はハードコードされています
  • Zip()呼び出しは、基本的に2つの隣接する番号をペアにします。
  • Zip()呼び出しは次の行の中央のみを生成するため、まだ先頭に1を追加し、最後に1を追加する必要があります
2
Hai Vu
# combining the insights from Aaron Hall and Hai Vu,
# we get:

def pastri(n):
    rows = [[1]]
    for _ in range(1, n+1):
        rows.append([1] +
                    [sum(pair) for pair in Zip(rows[-1], rows[-1][1:])] +
                    [1])
    return rows

# thanks! learnt that "shape shifting" data,
# can yield/generate elegant solutions.
1
ssgam
def Pascal(n):
    if n==0:
        return [1]
    else:
        N = Pascal(n-1)
        return [1] + [N[i] + N[i+1] for i in range(n-1)] + [1]


def Pascal_triangle(n):
    for i in range(n):
        print Pascal(i)
1
Abdel

これがエレガントで効率的な再帰的ソリューションです。非常に便利な toolz ライブラリを使用しています。

_from toolz import memoize, sliding_window

@memoize
def pascals_triangle(n):
    """Returns the n'th row of Pascal's triangle."""
    if n == 0:
        return [1]
    prev_row = pascals_triangle(n-1)
    return [1, *map(sum, sliding_window(2, prev_row)), 1]
_

pascals_triangle(300)は、macbook pro(2.9 GHz Intel Core i5)で約15ミリ秒かかります。デフォルトの再帰深度の制限を増やさなければ、これ以上高くすることはできないことに注意してください。

1
fredcallaway
# call the function ! Indent properly , everything should be inside the function
def triangle():

          matrix=[[0 for i in range(0,20)]for e in range(0,10)]         # This method assigns 0's to all Rows and Columns , the range is mentioned
          div=20/2           # it give us the most middle columns 
          matrix[0][div]=1        # assigning 1 to the middle of first row 
          for i in range(1,len(matrix)-1): # it goes column by column
               for j in range(1,20-1):  #  this loop goes row by row
                   matrix[i][j]=matrix[i-1][j-1]+matrix[i-1][j+1]               # this is the formula , first element of the matrix gets , addition of i index (which is 0 at first ) with third value on the the related row
    # replacing 0s with spaces :) 
          for i in range(0,len(matrix)):
              for j in range(0,20):
                   if matrix[i][j]==0:       #  Replacing 0's with spaces
                        matrix[i][j]=" "

          for i in range(0,len(matrix)-1):           # using spaces , the triangle will printed beautifully 
                for j in range(0,20):
                    print 1*" ",matrix[i][j],1*" ", # giving some spaces in two sides of the printing numbers
triangle() # calling the function

このようなものを印刷します

                       1
                1              1
           1           2            1
      1         3            3            1
  1        4        6            4               1
0

人気のある フィボナッチ数列 の解からごまかしています。私にとって、パスカルの三角形の実装はフィボナッチの同じ概念を持っているでしょう。フィボナッチでは、一度に1つの数値を使用し、それを前の数値に加算します。 Pascalの三角形では、一度に1つの行を使用し、前の行に追加します。

完全なコード例

_>>> def Pascal(n):
...     r1, r2 = [1], [1, 1]
...     degree = 1
...     while degree <= n:
...         print(r1)
...         r1, r2 = r2, [1] + [sum(pair) for pair in Zip(r2, r2[1:]) ] + [1]
...         degree += 1
_

テスト

_>>> Pascal(3)
[1]
[1, 1]
[1, 2, 1]
>>> Pascal(4)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
>>> Pascal(6)
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
_

:結果をジェネレーターとして使用するには、print(r1)を_yield r1_に変更します。

0
Aziz Alto

Beginner Python student here。これは、2つのForループを使用した非常に文字通りのアプローチです。

Pascal = [[1]]
num = int(input("Number of iterations: "))
print(Pascal[0]) # the very first row
for i in range(1,num+1):
    Pascal.append([1]) # start off with 1
    for j in range(len(Pascal[i-1])-1):
    # the number of times we need to run this loop is (# of elements in the row above)-1
        Pascal[i].append(Pascal[i-1][j]+Pascal[i-1][j+1])
        # add two adjacent numbers of the row above together
    Pascal[i].append(1) # and cap it with 1
    print(Pascal[i])
0
user3932000