第134回【Python】歴史を作る時間

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

はじめに

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

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

時間がかかりすぎて困るんです、と見せられた VBA が、ちょうど、最近やっている配列を用いた処理の部分でした。鼻高々で修正してどや顔をしておきました。まぁ、めったにあることではないので、たまにはいいじゃないですか。

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

歴史を作る時間

西暦 1,000,000,000 年に行われた歴史の授業のグループワークで、歴史上のいくつかの出来事についての記事を年代順に並べて歴史年表を作成することになりました。
ところが、歴史年表は 1 枚の紙にまとめる必要があるため、古い出来事を担当する人から順番に歴史年表を書くことにしました。
グループの人数 N とそのメンバー S_1 … S_N が与えられます。
続けて、歴史年表に載せる出来事の数 K , 各出来事の起こった年 Y_i , その出来事の記事を担当する生徒の名前 C_i が与えられるので、歴史年表を書く担当者の順番を出力してください。
なお、 1 人の生徒が複数の出来事の記事を担当することがある点に注意してください。

N K
S_1
...
S_N
Y_1 C_1
...
Y_K C_K

・1 行目では、グループの人数 N と歴史年表に載せる出来事の数 K が与えられます。
・続く N 行のうち i 行目では、 i 人目のメンバーの名前 S_i が与えられます。
・続く K 行のうち i 行目では、 i 個目の出来事の起こった年 Y_i と、その記事を担当する生徒の名前 C_i が先頭から順に与えられます。


すべてのテストケースにおいて、以下の条件をみたします。

・1 ≦ N ≦ 1,000
・1 ≦ K ≦ 100,000
・S_i は 20 文字以下の英数字列 (1 ≦ i ≦ N)
・S_i ≠ S_j (i ≠ j)
・1 ≦ Y_i ≦ 1,000,000,000 (1 ≦ i ≦ K)
・C_i は S_j のいずれか (1 ≦ i ≦ K , 1 ≦ j ≦ N)


入力例

3 5
nao
hiro
yuki
645 nao
593 hiro
2058 yuki
29484 nao
374759 nao

出力例

hiro
nao
yuki
nao
nao

地球は 10 億年後も人間が営みを続けているのだろうか。10 億年後に作る歴史年表に大化の改新なんて書いてもしょうがない気がする。もっと重要なことがたくさん起きているだろう・・・。

Python
N,K = map(int,input().split())
S = [input() for _ in range(N)]

histories = [None] * K

for i in range(K):
    Y,C = input().split()
    histories[i] = (int(Y),C)

for y,n in sorted(histories):
    print(n)
VBA
Sub query_primer__history()

    ti = Timer
    
    NK = Split(Cells(1, 1), " ")
    N = Val(NK(0))
    k = Val(NK(1))
    
    Dim A() As Variant
    ReDim A(k - 1)
    
    For i = 0 To k - 1
        s = Split(Cells(i + N + 2, 1), " ")
        year_ = Val(s(0))
        name_ = s(1)
        A(i) = Format(year_, "0000000000") & name_
    Next
    
    Call QuickSort(A, LBound(A), UBound(A))
    
    For Each v In A
        Debug.Print Mid(v, 11)
    Next
    
    Debug.Print Timer - ti
    
End Sub
Private Sub QuickSort(ByRef argAry() As Variant, ByVal lngMin As Long, ByVal lngMax As Long)

    Dim i As Long
    Dim j As Long
    Dim vBase As Variant
    Dim vSwap As Variant
    vBase = argAry(Int((lngMin + lngMax) / 2))
    i = lngMin
    j = lngMax
    Do
        Do While argAry(i) < vBase
            i = i + 1
        Loop
        Do While argAry(j) > vBase
            j = j - 1
        Loop
        If i >= j Then Exit Do
        vSwap = argAry(i)
        argAry(i) = argAry(j)
        argAry(j) = vSwap
        i = i + 1
        j = j - 1
    Loop
    If (lngMin < i - 1) Then
        Call QuickSort(argAry, lngMin, i - 1)
    End If
    If (lngMax > j + 1) Then
        Call QuickSort(argAry, j + 1, lngMax)
    End If
     
End Sub

いつもの境界値データで約 30 秒でした。

最後に

VBA で Debug.Print をしない場合、10 万件データを約 0.7 秒で処理しました。VBA にも夢があるね。

Python はわかりやすいコードが書けて素敵です。最近、配列を初期化するのに、[None]*N を用いているのですが、これが一番早いらしい、です。VBA でやろうとすると、初期化の時点では配列のサイズを変数で指定することができないので ReDim をする必要があり、ちょっと面倒くさい。

あと、ご指摘いただきましたが、Option Explicit は、普段はつける派です。ないと不安になる派です。Python との比較なので書いていないだけです。

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

Pythonpaiza,学習,Python

Posted by LeoSaki