CodeIQ:Excelなら簡単な集計

私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「Excelなら簡単な集計」(CodeIQ)を参照してください。

問題の概要

問題を引用します。

標準入力から与えられる気温データを元に、最高気温と最低気温でクロス集計を行うプログラムを作成してください。
今回は東京なので、-10度から40度までの範囲で5度ずつに区切って表示することにします。
(縦方向に最高気温、横方向に最低気温で集計します。)

例えば、次のようなデータが標準入力から与えられた場合、標準出力に以下の内容を出力するプログラムを作成してください。

【入力】
date,max,min
20140101,15.5,3.1
20140102,12.1,3.1
20140103,8.5,3.8
20140104,11.7,2.4
20140105,7.3,3.9
20140106,10.5,2.1
20140107,9.9,1.9
20140108,12.8,2.8
20140109,11.8,3
20140110,6.8,1.4
20140111,9,0.7
20140112,9.5,1.4
20140113,8.3,2.4
20140114,7.7,1.7
20140115,4.4,1.8
20140116,9.1,-0.2
20140117,9.5,2.9
20140118,8.6,2.8
20140119,7.1,2
20140120,8.5,0.7
20140121,11.8,1.8
20140122,9.6,2.1
20140123,11.1,2.8
20140124,12.6,2.4
20140125,12.4,3
20140126,14.5,2.4
20140127,7.5,1.4
20140128,15,1.1
20140129,12.8,4.9
20140130,15.8,5.1
20140131,15.9,6.2

【出力】
,-10<=min<-5,-5<=min<0,0<=min<5,5<=min<10,10<=min<15,15<=min<20,
20<=min<25,25<=min<30,30<=min<35,35<=min<40
-10<=max<-5,0,0,0,0,0,0,0,0,0,0
-5<=max<0,0,0,0,0,0,0,0,0,0,0
0<=max<5,0,0,1,0,0,0,0,0,0,0
5<=max<10,0,1,14,0,0,0,0,0,0,0
10<=max<15,0,0,11,0,0,0,0,0,0,0
15<=max<20,0,0,2,2,0,0,0,0,0,0
20<=max<25,0,0,0,0,0,0,0,0,0,0
25<=max<30,0,0,0,0,0,0,0,0,0,0
30<=max<35,0,0,0,0,0,0,0,0,0,0
35<=max<40,0,0,0,0,0,0,0,0,0,0
※ 1〜2行目の改行は見やすくするためのものです。実際には改行されません。

私のプログラム

Pythonで解答しています。

#!/usr/local/bin/python3
# -*- coding:utf-8 -*-

import sys
import fileinput
import math

lines = []
results = [[0 for j in range(10)] for i in range(10)]

#==============================================================================
# 結果を表示する
#------------------------------------------------------------------------------
def printResults():
    header_max = ["-10<=max<-5","-5<=max<0","0<=max<5","5<=max<10","10<=max<15",
                  "15<=max<20","20<=max<25","25<=max<30","30<=max<35","35<=max<40"]

    print(",-10<=min<-5,-5<=min<0,0<=min<5,5<=min<10,10<=min<15,15<=min<20,20<=min<25,25<=min<30,30<=min<35,35<=min<40")
    for i in range(10):
        sys.stdout.write(header_max[i])

        for j in range(10):
            sys.stdout.write("," + str(results[i][j]))

        sys.stdout.write("\n")

#==============================================================================
# 結果を作成する
#------------------------------------------------------------------------------
def checkPosition(line):
    day, tmax, tmin = map(str, line.split(","))
    tmax = float(tmax)
    tmin = float(tmin)

    pmax = math.floor((10+tmax) / 5)
    pmin = math.floor((10+tmin) / 5)

#    print("Max:" + str(tmax) + "(" + str(pmax) + ")"+ " Min:" + str(tmin) + "(" + str(pmin) + ")")

    results[pmax][pmin] += 1

#==============================================================================
# main
#------------------------------------------------------------------------------
LineNo = 0
for line in fileinput.input():
    if not line.strip():
        continue
    lines.append(line.strip())

    if LineNo:
        checkPosition(line.strip())

    LineNo += 1

printResults()

解説

確か、私がPythonを覚えようと思ってPythonで解答した(プログラムを1から作成する)最初の問題です。
問題自体は難しくありませんので丁度良いと思ってPythonでやってみた記憶があります。

checkPosition()

入力値をパースして集計結果を保持する2次元配列(results)の該当位置をカウントします。配列は0始まり、気温は-10から5℃刻みなので入力値を+10してから5で割って配列の要素番号に一致させています。
31行目は単にsplit()でよかったのですが、この辺りに慣れていない感じがあります。

printResult()

結果を表示します。単にresultsを順番に表示するだけです。
range()を使って配列番号によるアクセスをしていますが、resultsをイテレート(とPythonでも言うのかな?)し、さらにその要素をイテレートすればよかったのですが、この辺りも慣れていない感じが出ています。

雑感

問題とは全然関係ありませんが、これをやっていた時、行末に「;」をつけるかどうか悩んだのを覚えています。僕がこの時点で使える言語は大半が行末に「;」をつけるタイプだったので最初はつけようかと思ったのですが、つけてみたら関数宣言の後やif、forなどの最後につける「:」と紛らわしいのでやめました。一般的にPythonでは「;」はつけられないので妙な癖がつかなくてよかったと思っています。
最近、JavaやC/C++、PHPなどで「;」を付け忘れることがあるのがちょっと困ったところです。