2011-04-13 119 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)