簡體   English   中英

讀取CSV文件並在Python中對其進行排序

[英]Reading in a CSV file AND sorting it in Python

我試圖讀取一個看起來像這樣的CSV文件:

ruby,2,100
diamond,1,400
emerald,3,250
amethyst,2,50
opal,1,300
sapphire,2,500
malachite,1,60

這是我一直在嘗試的一些代碼。

class jewel:
    def __init__(gem, name, carat, value):
            gem.name = name
            gem.carot = carat
            gem.value = value
    def __repr__(gem):
            return repr((gem.name, gem.carat, gem.value))

jewel_objects = [jewel('diamond', '1', 400),
                 jewel('ruby', '2', 200),
                 jewel('opal', '1', 600),
                ]

aList = [sorted(jewel_objects, key=lambda jewel: (jewel.value))]
print aList

我想讀取值並將它們分配給name,carat和value,但我不知道該怎么做。 然后,一旦我把它們讀入,我想按每克拉的價值這樣的價值/克拉對它們進行分類。 我做了很多搜索,並且空白了。 非常感謝您的幫助。

你需要在這里做兩件事,第一件事實際上是將數據加載到對象中。 我建議您查看標准python庫中的'csv'模塊。 它非常完整,將讀取每一行並使其易於訪問

CSV文檔: http//docs.python.org/library/csv.html

我會創建一個對象列表,然后在你的對象中實現一個cmp函數,或者(如果你使用的是舊版本的python)你可以將一個函數傳遞給定義它的sorted()。 您可以在python wiki中獲得有關排序的更多信息

Wiki docs: http//wiki.python.org/moin/HowTo/Sorting

你可以在你的類中實現這樣的cmp函數(這可以更高效,但我在這里描述)

def __cmp__(gem, other):
    if (gem.value / gem.carot) < (other.value / other.carot):
        return -1
    elif (gem.value / gem.carot) > (other.value / other.carot): 
        return 1
    else:
        return 0

Python有一個csv模塊應該對你有用。

http://docs.python.org/library/csv.html

您可以將numpy結構化數組與csv模塊一起使用,並使用numpy.sort()對數據進行排序。 以下代碼應該有效。 假設您的csv文件名為geminfo.csv

import numpy as np
import csv

fileobj = open('geminfo.csv','rb')
csvreader = csv.reader(fileobj)

# Convert data to a list of lists
importeddata = list(csvreader)

# Calculate Value/Carat and add it to the imported data
# and convert each entry to a tuple
importeddata = [tuple(entry + [float(entry[2])/entry[1]]) for entry in importeddata]

對數據進行排序的一種方法是使用numpy,如下所示。

# create an empty array
data = np.zeros(len(importeddata), dtype = [('Stone Name','a20'),
                            ('Carats', 'f4'),
                            ('Value', 'f4'), 
                            ('valuepercarat', 'f4')]
                        )
data[:] = importeddata[:]
datasortedbyvaluepercarat = np.sort(data, order='valuepercarat')

要解析實際CSV(逗號分隔值)數據,您需要使用最新版本的Python附帶的CSV模塊。

CSV是一組約定而不是標准。 您顯示的示例數據簡單而有規律,但CSV通常有一些丑陋的角落案例,用於引用任何字段的內容可能嵌入逗號的位置。

這是一個非常粗略的程序,基於你的代碼,它對數據進行天真的解析(按行分割,然后在逗號上分割每一行)。 它不會處理任何不能精確分割到正確數量的字段的數據,也不會處理Python int()float()函數(對象構造函數)未正確解析數字字段的任何數據。 換句話說,它不包含錯誤檢查和異常處理。

但是,我保持它故意簡單,所以它可以很容易地與您的粗略筆記進行比較。 另請注意,我在類定義中使用了關於“self”引用的常規Python約定。 (關於唯一一次使用除“self”之外的名稱的人,就是在進行“元級”編程時...編寫動態實例化其他類的類。任何其他情況幾乎肯定會引起任何人心中的嚴重關注。經驗豐富的Python程序員查看您的代碼)。

#!/usr/bin/env python
class Jewel:
    def __init__(self, name, carat, value):
        self.name = name
        self.carat = int(carat)
        self.value = float(value)
        assert self.carat != 0      # Division by zero would result from this
    def __repr__(self):
        return repr((self.name, self.carat, self.value))

if __name__ == '__main__':
    sample='''ruby,2,100
diamond,1,400
emerald,3,250
amethyst,2,50
opal,1,300
sapphire,2,500
malachite,1,60'''

    these_jewels = list()
    for each_line in sample.split('\n'):
        gem_type, carat, value = each_line.split(',')
        these_jewels.append(Jewel(gem_type, carat, value))
        # Equivalently: 
        # these_jewels.append(Jewel(*each_line.split(',')))

    decorated = [(x.value/x.carat, x) for x in these_jewels]
    results = [x[1] for x in sorted(decorated)]
    print '\n'.join([str(x) for x in results])

這里的解析只是使用字符串.split()方法完成,並使用Python的“元組解包”語法將數據提取到名稱中(如果任何輸入行具有錯誤的字段數,這將失敗)。

這兩行的替代語法使用Python的“apply”語法。 參數上的*前綴使其被解壓縮為單獨的參數,這些參數將傳遞給Jewel()類實例化。

此代碼還使用廣泛(且廣泛推薦)的DSU(裝飾,排序,未裝飾)模式對數據的某些字段進行排序。 我通過創建一系列元組來“裝飾”數據:(計算值,對象引用),然后以我希望對你清楚的方式“解開”排序數據。 (任何有經驗的Python程序員都會立即明白)。

是的,整個DSU可以減少到一條線; 我把它分開是為了易讀性和教學目的。

此示例代碼再次純粹是為了您的啟發。 您應該在任何真實數據上使用CSV模塊; 你應該在解析或者Jewel.__init__處理中引入異常處理(用於將數值數據轉換成正確的Python類型。)另外請注意,你應該考慮使用Python的Decimal模塊而不是float()來表示貨幣值......或者至少以美分或密碼存儲值,並使用您自己的函數將這些值表示為美元和美分。

import csv
import operator

class Jewel(object):
    @classmethod
    def fromSeq(cls, seq):
        return cls(*seq)

    def __init__(self, name, carat, value):
        self.name  = str(name)
        self.carat = float(carat)
        self.value = float(value)

    def __repr__(self):
        return "{0}{1}".format(self.__class__.__name__, (self.name, self.carat, self.value))

    @property
    def valuePerCarat(self):
        return self.value / self.carat

def loadJewels(fname):
    with open(fname, 'rb') as inf:
        incsv = csv.reader(inf)
        jewels = [Jewel.fromSeq(row) for row in incsv if row]
    jewels.sort(key=operator.attrgetter('valuePerCarat'))
    return jewels

def main():
    jewels = loadJewels('jewels.csv')
    for jewel in jewels:
        print("{0:35} ({1:>7.2f})".format(jewel, jewel.valuePerCarat))

if __name__=="__main__":
    main()

產生

Jewel('amethyst', 2.0, 50.0)        (  25.00)
Jewel('ruby', 2.0, 100.0)           (  50.00)
Jewel('malachite', 1.0, 60.0)       (  60.00)
Jewel('emerald', 3.0, 250.0)        (  83.33)
Jewel('sapphire', 2.0, 500.0)       ( 250.00)
Jewel('opal', 1.0, 300.0)           ( 300.00)
Jewel('diamond', 1.0, 400.0)        ( 400.00)    

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM