第18回【Python】さまざまな長さの配列の和、階段の出力、二重ループ:基本編

現在取り組んでいるのは、paiza ラーニング問題集「二重ループメニュー」になります。

はじめに

猫とキャンプと野球観戦と AWS が大好きな旦那、LeoSaki です。モフモフしたい。

Python をゼロから勉強してみよう、のコーナー 18 回目です。

エースナンバー 18 ! なぜエースナンバーが背番号 18 かは諸説あるようだが、藤田 → 堀内 → 桑田の流れが一番大きいと思う。杉内、菅野が、18 を汚しているような気がする。(LeoSaki(旦那)はプロの選手としてお金をもらっている以上、成績が伴わなければバッシングされるのは仕方ないと考える派だ。会社でミスすれば怒られるし、始末書書かなきゃだし、賞与査定にも響くでしょ? なんでプロ野球の選手はボコボコホームラン打たれて(それも 1 度や 2 度でなく!)次があるから頑張れって拍手されるん? パワプロでは確実に一発病が 10 個くらいつくレベルやん。菅野くん)

超話がそれてしまった。我がジャイアンツに「エース」が欲しいものです。

それでは、今日も頑張ってみようと思います。

さまざまな長さの配列の和

整数 N が与えられるので、次の処理を N 回してください。
・ 配列のサイズ K とその要素 A1 … AK が与えられるので、全ての要素の和を求めて出力してください。

配列のサイズ K がポイントとみた! 考え方次第では、二重ループが不要な気がする。けれども、テーマは二重ループなのだから、きちんと二重ループで書いてみよう。

Python
N = int(input())
for _ in range(N):
    X = list(map(int,input().split()))
    K = X[0]
    ans = 0
    for i in range(1,K + 1):
        ans += X[i]
    print(ans)

ちなみに、最初に書いたコードがこれ。

Python
N = int(input())
a = [[int(x) for x in input().split()] for _ in range(N)]
for i in range(N):
    del a[i][0]
    print(sum(a[i]))

いろいろ端折りすぎだった。わざわざ del とかしなくても、sum(a[i][1:]) と Python らしく書いた方が美しかった気がしている。

さて、毎度の VBA で書いてみよう。

VBA
N = Cells(1, 1)
For i = 1 To N
    S = Split(Cells(1 + i, 1), " ")
    K = Val(S(0))
    ans = 0
    For j = 1 To K
        ans = ans + S(j)
    Next
    Debug.Print (ans)
Next

これはこれでわかりやすい。というか、ほぼ Python と同じコードで書ける。

階段の出力

整数 N が与えられるので、次の規則に従って N 行の出力をしてください。
・ N 行のうち、 i 行目では、1 から i までの数字を半角スペース区切りで出力してください。

例として、 N = 3 のとき、出力は次の通りになります。

1
1 2
1 2 3

こういうのってプログラミングを始めた頃、何かしらの課題でやったりしませんでした? LeoSaki(旦那)は、いろんな言語で書いてみた記憶があるのだけれど。

Python
N = int(input())
for i in range(1,N + 1):
    for j in range(1,i + 1):
        if j == i:
            print(j)
            break
        print(j,end=" ")

for 文で指定なければ 0 から始まる。range 関数では、range(開始,終了,増加量)が指定できる。1 を開始とした場合は、終了も 1 増やしておかなければならない。

もし、range 関数で開始も終了も指定しなかったら、次のようなコードになる。

Python
N = int(input())
for i in range(N):
    for j in range(i + 1):
        if j == i:
            print(j + 1)
            break
        print(j + 1,end =" ")

なんか分かりづらい。

いつも通り、VBA でも挑戦してみよう。

VBA
N = Cells(1, 1)
For i = 1 To N
    For j = 1 To i
        If j = i Then
            Debug.Print j
            Exit For
        End If
        Debug.Print j;
    Next
Next

for 文の書き方的には、VBA の方が分かりやすいコードになった。

二重ループ:基本編

配列 A と B についての情報が与えられるので、(A の 1 つの要素) × (B の 1 つの要素) の最大値を求めてください。

N K
A_1 A_2 ... A_N
B_1 B_2 ... B_K

・ 1 行目では、配列 A の要素数を表す整数 N と配列 B の要素数を表す整数 K が半角スペース区切りで与えられます。
・ 2 行目では、配列 A の各要素が半角スペース区切りで与えられます。
・ 3 行目では、配列 B の各要素が半角スペース区切りで与えられます。

すべてのテストケースにおいて、以下の条件をみたします。
・ 1 ≦ N , K ≦ 100
・ -100 ≦ A_i , B_j ≦ 100 (1 ≦ i ≦ N, 1 ≦ j ≦ K)

最大値を求める問題では、条件をきちんと確認しておく必要がある。最大値をあらかじめ変数に入れておく際に、0 なんて設定しておくと、例えば、配列の片方がすべてマイナスであった場合に痛い目をみてしまう。

配列 A -10 -15 -20 -25 -30 -35 -40 -45 -50
配列 B 1 2 3 4 5 9 7 8 9 10

この場合の最大値は、-10 となり、0 よりも小さくなる。こんなミスを犯してしまったのは誰か。LeoSaki(旦那)です。とても残念。

Python
N,K = map(int,input().split())
A = [int(x) for x in input().split()]
B = [int(x) for x in input().split()]
max_ans = -10000
for a in A:
    for b in B:
        ab = a*b
        if max_ans < ab:
            max_ans = ab
print(max_ans)

ああ、また、与えられた N と K を使っていない。でも、こういう書き方ができるのが Python のいいところなんだから、これでいいじゃないか! 一応、ちゃんと与えられた N と K を使った回答を考えよう。

Python
N,K = map(int,input().split())
A = [int(x) for x in input().split()]
B = [int(x) for x in input().split()]
max_ans = -10000
for i in range(N):
    for j in range(K):
        ab = A[i] * B[j]
        if max_ans < ab:
            max_ans = ab
print(max_ans)

もちろん、これも、VBA で挑戦してみる。

VBA
S = Split(Cells(1, 1), " ")
N = Val(S(0))
K = Val(S(1))
A = Split(Cells(2, 1), " ")
B = Split(Cells(3, 1), " ")
max_ans = -10000
For i = 0 To UBound(A)
    valA = Val(A(i))
    For j = 0 To UBound(B)
        ab = valA * Val(B(j))
        If max_ans < ab Then max_ans = ab
    Next
Next
Debug.Print max_ans

一つ目の for 文直後に val 関数を利用して値を整数としておくことで、計算量をほんのちょっとでも減らそうという涙ぐましい努力をしてみた。しかし、99 × 99 の 9801 通りの掛け算くらいでは、差を感じることができなかった。

最後に

ようやく二重ループの基本編が終わったようだ。こうやって 1 問 1 問地道に解いていくのは嫌いじゃない。こうすればもっと早くなるのでは? なんて考えているだけで、どんどん時間が過ぎていく。この時間泥棒め!

Python を学習していると、Python らしい書き方、っていうので書いてみたくなる。Python って独特で面白い。その独特さがわかりやすいのがいい。・・・Ruby も一時期書いてみたけれど、正直ね、わかりづらい部分があったなぁ。もちろん、Ruby がダメってわけではなく!

少しずつボリュームのあるコードになってきたので、実行時間を気にして、出来るだけ少ない計算量となるコードを書けたらいいなぁと思っとります。

引き続き、お付き合いよろしくお願いいたします!

Python学習,Python,paiza

Posted by LeoSaki