2011-04-13 113 views
0

排序它,我試圖看起來像這樣一個CSV文件讀取:讀入一個CSV文件,並在Python

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 

我想讀取值並將它們分配給名稱,克拉和值,但我不知道如何去做。然後,一旦我獲得了他們的閱讀,我想按照每克拉的價值對它們進行分類,因此價值/克拉。我做了很多搜索,並且空白了。提前感謝您的幫助。

+0

什麼是「寶石」,是一個基類? – 2011-04-13 00:57:56

+0

@Mike,看起來像拼寫錯誤self':D – 2011-11-26 01:54:09

回答

2

您需要做兩件事情,第一是數據實際加載到目標。我建議你看一下標準python庫中的'csv'模塊。這是非常完整的,會讀每一行並使其易於accessable

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

我會創建對象的列表,然後執行任意的CMP在你的目標函數,或者(如果你使用的是舊版本的python),你可以傳遞一個函數給sorted()來定義它。你可以得到更多的信息關於在Python維基排序

維基文檔:http://wiki.python.org/moin/HowTo/Sorting

你會實現你的類CMP功能這樣的(這可以做多一點efficent,但我是描述在這裏)

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 
+0

爲了完整性,'__cmp__'已折舊並已從python 3中刪除,所以最好使用__ne__,__eq__,__lt__,__gt__,__le__,__ge__ ,比較方法。 – 2011-04-13 01:14:10

+0

廢話,你知道我需要重寫多少代碼! – 2011-04-13 01:27:02

+0

好,因爲它的蟒蛇...希望沒有那麼多(和任何你沒有移植到3,也不應該擔心它)) – 2011-04-13 02:32:15

0

您可以使用numpy的結構化陣列,csv模塊一起,並使用numpy.sort()對數據進行排序。下面的代碼應該可以工作。假設您的CSV文件被命名爲排序這一數據是使用numpy的,如下圖所示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] 

的一種方式。

# 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') 
+0

我看不出Numpy爲這種方法增加了什麼樣的價值(比較簡單地使用標準庫附帶的標準Python特性和模塊)。 – 2011-04-13 02:28:31

+0

他還想將值分配給他正在創造珠寶類的「名字」,「克拉」和「價值」。有了numpy結構化數組,他可以在不創建珠寶類的情況下實現這一點。 – Curious2learn 2011-04-13 10:57:07

+0

但是創建一個類是Python的一個內置功能,可以作爲實現他想要用他的珠寶做的任何事情的基礎;因此我的問題是:爲什麼當他的需求看起來比Numpy適合的規模和語義要簡單得多時,爲什麼要引入一個龐大而複雜的外部依賴(以及該包和其類型的額外認知開銷)? – 2011-04-13 19:57:30

0

爲了解析真實世界的CSV(逗號分隔值),你想使用隨機配備有最新版本的Python的CSV模塊的數據。

CSV是一套規範,而不是標準的。您顯示的示例數據非常簡單且規則,但CSV通常會有一些難以處理的角落情況,例如,引用任何字段的內容可能包含逗號的位置。

這裏是一種非常粗糙的程序,是根據你的代碼,它執行數據的幼稚解析(由線分割,然後分裂的逗號每線)。它不會處理其不被劃分到精確的正確數目的字段,也沒有任何的數據的任何其中數字字段不由Python int()float()函數(對象構造)正確分析。換句話說,這不包含錯誤檢查或異常處理。

不過,我已經把它刻意簡單,所以它可以很容易地相比,你粗糙的筆記。另請注意,我在類定義中使用了有關「自我」引用的常規Python約定。 (關於唯一一次使用「自我」以外的名字的時候,是在做「元類」編程時......編寫動態實例化其他類的類,其他任何情況幾乎肯定會引起任何人的頭腦中的嚴重擔憂經驗豐富的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(裝飾,排序,undecorate)模式對數據的某些字段進行排序。我通過創建一系列元組來「修飾」數據:(計算值,對象引用),然後以我希望清楚的方式「排除」排序後的數據。 (任何有經驗的Python程序員都會立即明白)。

是的,整個DSU可以縮減爲一行;爲了易讀性和教學目的,我在此將其分開。

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

0
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)