使用嵌套for循环迭代csvDictReader

2024-10-03 04:29:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难理解如何正确地迭代csvDictReader对象。用户定义的csv值返回我绑定的每个代码。因为我是从一个web查询生成dict,所以我希望在内存中重用它,而不是再次在web上轮询已经存在于内存中的数据。在

import sys, csv, urllib2
class SmfImpl():

    def __init__( self, ctx ):
        self.ctx = ctx
        self.csv_dict = []
        self.flag = ['Not Available', '']
        self.ticker = 'XOM'

    def getMorningKey(self, datacode):
        return fetch_keyratios(self, datacode)

#these functions are not in the SmfImpl class because they're from a seperate file
def query_morningstar(self, url_ending): 
        url = 'http://financials.morningstar.com/ajax/exportKR2CSV.html?&callback=?&t=XNYS:%s%s' % (self.ticker, url_ending)
        req = urllib2.Request(url)
        response = sniff_query(req)
        response.readline()
        return csv.DictReader(response)

def sniff_query(req):
    try:
        response = urllib2.urlopen(req)
    except urllib2.URLError:
        return 'Check Connection'
    sniff = response.readline()
    if str(sniff) == '':
        return 'Not Available'
    return response

def fetch_keyratios(self, datacode):
    if datacode < 1 or datacode > 990:
        return 'Invalid Datacode'
    #check if we already have the data we need
    if self.flag[0] == 'Check Connection' or self.flag[0] == 'Not Available' or self.flag[1] != self.ticker:
        #query remote and check for errors
        self.csv_dict = query_morningstar(self,'&region=usa&culture=en-US&cur=USD&order=desc')
        if self.csv_dict == 'Check Connection' or self.csv_dict == 'Not Available':
            self.flag[1] = ''
            return self.csv_dict
        else:
            self.flag[0] = ''
            self.flag[1] = self.ticker
    return sort_keyratios(self, datacode)

def sort_keyratios(self, datacode):       
    counter = 1
    skipped = 0
    skip_lines = [15, 16, 26, 36, 37, 57, 58, 64, 65, 86, 91, 92]            
    #iterate through returned dict line by line
    for line in self.csv_dict:
        for item in skip_lines:
            if counter == item:
                skipped += 1
        for val in range(1, len(line)):
            #match year values to datacodes
            if datacode == val:
                return self.csv_dict.fieldnames[val]
            #match data values to datacodes
            if datacode-((counter-skipped)*(len(line)-1)) == val:
                return line[self.csv_dict.fieldnames[val]]
        counter += 1
    return 'No Data'

if __name__ == "__main__":
    smf = SmfImpl(sys.argv)
    ticker = 'XOM'
    for val in range (1,24):
        print ticker, val,':', smf.getMorningKey(val)

原始csv由脚本调用,但也可以找到here

我得到的输出是:

^{pr2}$

我想要的是:

XOM 1 : TTM
XOM 2 : 2012-12
XOM 3 : 2011-12
XOM 4 : 2010-12
XOM 5 : 2009-12
XOM 6 : 2008-12
XOM 7 : 2007-12
XOM 8 : 2006-12
XOM 9 : 2005-12
XOM 10 : 2004-12
XOM 11 : 2003-12
XOM 12 : 443,708
XOM 13 : 482,295
XOM 14 : 486,429
XOM 15 : 383,221
XOM 16 : 310,586
XOM 17 : 477,359
XOM 18 : 404,552
XOM 19 : 377,635
XOM 20 : 370,680
XOM 21 : 298,035
XOM 22 : 246,738
XOM 23 : 27.8

编辑:我正在尝试映射数据代码分组每行原始csv。e、 g年将是数据代码1到11(TTM到2003-12),收入将是数据代码12到22(443708到246738)等等。最终这些数据代码将被移动到用户输入中,因此可以以任何顺序访问它们。在


Tags: csv数据代码selfreturnifresponsedef
3条回答

下面是我该怎么做的。它将产生你想要的输出。我已经重新格式化了一些代码,以便更好地适应stackoverflow上的代码列表框。棘手的部分是找出读入内存中矩阵的数据的datacode到{}的映射。在

import sys, csv, urllib2
class SmfImpl():
    def __init__( self, ctx ):
        self.ctx = ctx
        self.csv_reader = ''
        self.flag = ['Not Available', '']
        self.ticker = 'XOM'

    def getMorningKey(self, datacode):
        return fetch_keyratios(self, datacode)

#these functions are not in the SmfImpl class because they're in a seperate file
def query_morningstar(self, url_ending):
    MORNING_STAR = 'http://financials.morningstar.com/ajax/exportKR2CSV.html'
    url = MORNING_STAR + '?&callback=?&t=XNYS:%s%s' % (self.ticker, url_ending)
    req = urllib2.Request(url)
    response = sniff_query(req)
    response.readline()
    return csv.reader(response)

def sniff_query(req):
    try:
        response = urllib2.urlopen(req)
    except urllib2.URLError:
        return 'Check Connection'
    sniff = response.readline()
    if str(sniff) == '':
        return 'Not Available'
    return response

def fetch_keyratios(self, datacode):
    if datacode < 1 or datacode > 990:
        return 'Invalid Datacode'
    #check if we already have the data we need
    if(self.flag[0] == 'Check Connection' or
       self.flag[0] == 'Not Available' or self.flag[1] != self.ticker):
        #query remote and check for errors
        self.csv_reader = query_morningstar(self,
                                '&region=usa&culture=en-US&cur=USD&order=desc')
        if(self.csv_reader == 'Check Connection' or
           self.csv_reader == 'Not Available'):
            self.flag[1] = ''
            return self.csv_reader  # actually response status message
        else:
            self.flag[0] = ''
            self.flag[1] = self.ticker
            # read entire dataset in memory skipping lines as neccessary
            self.data = [row[1:] for row in self.csv_reader if len(row) == 12]

    return sort_keyratios(self, datacode)

def sort_keyratios(self, datacode):
    # convert datacode to row, column and return data in that position of list
    row, col = divmod(datacode-1, 11)
    return self.data[row][col]

if __name__ == "__main__":
    smf = SmfImpl(sys.argv)
    ticker = 'XOM'
    for val in range(1, 24):
        print ticker, val,':', smf.getMorningKey(val)

使用csv.reader()代替csv.DictReader,因为您并没有真正使用列/字段名。第一次调用getMorningKey()时,响应中的所有数据(除了少数第一行)都被读入并存储在一个列表列表中。以这种方式读取的每一行都应该是12个项目的列表,任何未跳过的项目都将被跳过。此外,为了使数据代码的映射更容易,只保存最后11个条目。结果是一个二维矩阵,其中行是行号,列是字段号。我创建的这个web page上显示了Exxon示例ticker的原始矩阵数据视图。在

正如您所看到的,这种方法极大地简化了逻辑,而且由于它将所有数据存储在内存中,因此它将在后续调用中重用,并使随机访问成为可能,而无需再次执行查询。在

输出如下:

^{pr2}$

马蒂诺贴出的答案是正确的。为了完成并获得我最初寻找的功能,我将sort\u keyriotios更改为以下内容:

def sort_keyratios:    
    #define rows that have no useful data   
    skip_list = [16,17,18,28,29,38,39,40,41,46,51,56,61,62,63,69,70,71,92,93,98,99,100]
    skipped = 0
    # match datacode to row, column and return data in that position of list
    for row in range(0,109):
        if row in skip_list:
            skipped+=11
            continue
        for col in range(0,12):
            if datacode == col+(11*row)-skipped:
                return self.data[row][col]

这是对您在自己的问题的答案中对sort_keyratios()所做的修改作出的回应。如果你发现其他有用的信息,你还有其他事情要投票。<;提示>

总之,您可以更有效地完成正在做的事情,方法是构建一个字典,将每个datacode映射到一个(row, col)对,然后使用这个先前构建的表来查找函数中的值。为了方便起见,我添加了一个名为create_datacode_map()的新函数。在

以下是如何使用它:

def create_datacode_map():
    """ Create dictionary mapping datacodes to (row, col) in data. """
    # define rows that have no useful data
    skip_list = {16, 17, 18, 28, 29, 38, 39, 40, 41, 46, 51, 56, 61, 62, 63, 69,
                 70, 71, 92, 93, 98, 99, 100}
    def find_row_col(datacode):
        skipped = 0
        # match datacode to row, column
        for row in xrange(0, 109):
            if row in skip_list:
                skipped += 11
                continue
            for col in xrange(0, 12):
                if datacode == col + (11*row) - skipped:
                    return row, col

    # create and return the dictionary
    return {datacode: find_row_col(datacode) for datacode in xrange(1, 910)}

def sort_keyratios(self, datacode):
    # convert datacode to row, column and return data in that position of list
    if not hasattr(self, 'datacode_map'):
        self.datacode_map = create_datacode_map()
    row, col = self.datacode_map[datacode]  # lookup conversion
    return self.data[row][col]

所示的sort_keyratios()版本在每次调用时都检查self.datacode_map是否存在,如果不存在,则创建它。如果已经在fetch_keyratios(()中完成了该操作,那么sort_keyratios()就可以假定它存在,而不必每次调用它时都进行检查。在

相关问题 更多 >