Python 使用嵌套for循环迭代csvDictReader
我很难理解如何正确地迭代csvDictReader对象。我试图返回每个绑定到特定用户定义数据代码的csv值。因为我是从一个web查询生成dict,所以我希望在内存中重新使用它,而不是再次轮询web以查找内存中已经存在的数据Python 使用嵌套for循环迭代csvDictReader,python,csv,for-loop,Python,Csv,For Loop,我很难理解如何正确地迭代csvDictReader对象。我试图返回每个绑定到特定用户定义数据代码的csv值。因为我是从一个web查询生成dict,所以我希望在内存中重新使用它,而不是再次轮询web以查找内存中已经存在的数据 import sys, csv, urllib2 class SmfImpl(): def __init__( self, ctx ): self.ctx = ctx self.csv_dict = [] self.f
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,'®ion=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)
我想要得到的是:
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),等等。最终这些数据代码将被移动到用户输入,因此可以以任何顺序访问它们。我将这样做。它将产生你想要的输出。我对代码进行了一些重新格式化,以便更好地适应stackoverflow上的代码列表框。棘手的部分是找出
datacode
到row,column
的映射,这些数据被读取到内存中的矩阵中
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,
'®ion=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)
马蒂诺发布的答案是正确的。为了完成并获得我最初寻找的功能,我将sort_keyratios更改为以下内容:
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\u keyrations()
所做的修改。如果你觉得额外的信息有用的话,你还可以选择其他的东西
无论如何,您可以通过构建一个字典,将每个datacode
映射到(行,列)
对一次,然后使用这个先前构建的表来查找函数中的值,从而更高效地完成正在做的事情。为了方便起见,我添加了一个名为create\u datacode\u 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\u keyrations()
版本在每次调用时检查是否存在self.datacode\u map
,如果不存在则创建它。如果在fetch\u keyrations(()
sosort\u keyrations()中已经这样做了,那么效率会更高
可以假设它存在,而不必每次调用时都检查它。val/datacodes是否总是按升序访问?是否可以将整个csv读取到内存中?否,main中定义的ticker和val最终都将移动到user input/sys.argv,因此可以按任何顺序访问值r、 首先,这意味着每次至少重新读取csv数据的一部分,因为csv.DictReader
以顺序方式访问数据——这就是为什么我建议将整个数据读取到内存中,允许随机访问(以及在调用之间保留它)。此外,您的问题还需要添加其他信息来解释数据代码到csv文件中位置的映射,因为代码和其中的一些注释不够清晰。坦白地说,我不清楚您为什么要使用csv.DictReader
来尝试此操作。我编辑了原始帖子以澄清这一点数据代码映射。我最初将其实现为1 urlrequest->1脚本输出,csvDictReader似乎是正确的方法。我认为现在我在本地重新使用数据,csvDictReader可能不是最好的方法,但我不确定如何按照您的建议在内存中实现此功能。好的,这很有帮助。如果在这种情况下,XOM 23
的期望值不应该是27.8
而不是28.7
?另外,计数器也是排序键比率()
这是您自己试图解决问题的产物?这让我走上了正确的道路。真的,非常感谢。我发布了一个答案,它完成了我正在寻找的功能,以防对其他人有所帮助。这感觉就像回到了一个dict的完整循环映射。我相信您已经推断出我正在学习python谢谢你的代码中的解释和微妙之处,它们帮助我指导了我自己的学习(即xrange()
vsrange()
,尽管我可能会发现自己受制于Python 3,所以可能会坚持range()
)。你为什么要使用find\u row\u col()
是一个子函数,而不是将该代码留在create\u datacode\u map()
中?是的,这是另一个字典,但它的用途完全不同。Python有从版本2转换到版本3的工具,可以修复xrange
的使用,因此我不会因此而避免它。我制作了find\u row\u col()
一个嵌套函数,因为它只由create\u datacode\u map()
调用,并且它允许在函数本身之外创建skip\u list
,而不是每次调用它。
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]