读取CSV文件并在Python中对其进行排序

时间:2011-04-13 00:53:48

标签: python file sorting csv

我正在尝试读取如下所示的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,但我不知道该怎么做。然后,一旦我把它们读入,我想按每克拉的价值这样的价值/克拉对它们进行分类。我做了很多搜索,并且空白了。非常感谢您的帮助。

5 个答案:

答案 0 :(得分:2)

你需要在这里做两件事,第一件事实际上是将数据加载到对象中。我建议您查看标准python库中的'csv'模块。它非常完整,将读取每一行并使其易于访问

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

我会创建一个对象列表,然后在你的对象中实现一个 cmp 函数,或者(如果你使用的是旧版本的python)你可以将一个函数传递给sort ()将定义它。您可以在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

答案 1 :(得分:0)

Python有一个对你真有帮助的csv模块。

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

答案 2 :(得分:0)

您可以将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')

答案 3 :(得分:0)

要解析真实世界的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()来表示货币值...或者至少以美分或密码存储值,并使用您自己的函数将这些值表示为美元和美分)。

答案 4 :(得分: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)