星期二, 9月 07, 2010

python怎麼sort dictionary?

為了做一個統計的圖表, 我對python的list操作又熟悉了一點.

這是要用server蒐集到的一堆資料, 做幾張圓餅圖. 那些資料會被統計為"A發生n次, B發生m次, C發生i次, D發生j次", 以此類堆. 可能有數十到數百種, 每個的發生次數不一, 從個位數到幾千幾萬都有可能.
這樣的Data讀進來的時候, 就是以dictionary的型式. 所以大概是長成{'A': n, 'B': m, 'C': i, 'D': j}, 這個樣子. 而它的內容是沒有經過排序的. 這樣做出來的圓餅圖就會大小參差不齊的幾塊小pizza, 不太好看. 所以我想把它sort過, 然後後面幾項小的項目, 就把數字相加, 統一當作Others. 這樣視覺上可以直接看得出最重要的幾筆.

所以我需要一個function, 參數是該dictionary, 跟幾筆之後的項目要被加起來當作Others. 一開始是這麼做的.

方法一
def sortbyvalue(dict, order_count):
    keys = [dict.keys()[0]]
    values = [dict.values()[0]]
    others_value = 0

    for i in range(1, len(dict)):
        j = 0
        for j in range(len(values)):
            if value[j] < dict.values()[i]:
            break

        if j == len(values) - 1 and values[j] >= dict.values()[i]:
            keys[j+1:j+1] = [dict.keys()[i]]
            values[j+1:j+1] = [dict.values()[i]]
        else:
            keys[j:j] = [dict.keys()[i]]
            values[j:j] = [dict.values()[i]]

    if len(values) > order_count:
        for value in values[order_count:]:
            others_value = others_value + value

    keys = keys[0:order_count]
    values = values[0:order_count]

    if others_value != 0:
        keys.append('Others')
        values.append(others_value)

    return (keys, values)
這個落落長的function, 能看懂的人大概不多吧. 後來在網路上找到sort dictionary的方法, 於是有了方法二.

方法二
def sortbyvalue(dict, order_count):
    di = dict.items()
    di.sort(key=lambda x: x[1], reverse=True)

    keys = []
    values = []
    others_value = 0

    if len(di) > order_count:
        for item in di[order_count:]:
            others_value = others_value + item[1]

    for i in range(min(len(di), order_count)):
        keys.append(di[i][0])
        values.append(di[i][1])

    if others_value != 0:
        keys.append('Others')
        values.append(others_value)

    return (keys, values)
這個方法主要是改善了sort的方式, 不再是用原本的"insertion sort", 而是用內建的sort(). 不過後面的算總和跟處理list的地方, 還是很不道地. 於是又有了方法三.

方法三
def sortbyvalue(dict, order_count):
    di = dict.items()
    di.sort(key=lambda x: x[1], reverse=True)

    keys = [x[0] for x in di]
    values = [x[1] for x in di]
    others_value = sum(values[order_count:])

    keys = keys[:order_count]
    values = values[:order_count]

    if others_values != 0:
        keys.append('Others')
        values.append(others_value)

    return (keys, values)
我相信應該還可以再寫得更精簡一點, 不過現在這個樣子我就可以接受了.

沒有留言: