创建数组后,如何正确遍历 CSV 文件中的行数组?

Posted

技术标签:

【中文标题】创建数组后,如何正确遍历 CSV 文件中的行数组?【英文标题】:How to properly iterate through an array of rows from a CSV file, after the array has been created? 【发布时间】:2018-03-30 12:48:35 【问题描述】:

非常抱歉,如果之前回答过这个问题,但我搜索了 *** 并找不到解决问题的明确解决方案。

我有一个名为“myFile.csv”的 CSV 文件

文件以逗号 (“,”) 分隔 第一行包含列标题,而所有后续行都是数据行。

我打开并读取 CSV 文件,将每一行分配给一个名为“myArray”的数组,以便稍后用于不同的事情……

with open("..\dirX\myFile.csv", 'rb') as fileHandle:
    myArray = []
    for row in csv.reader(fileHandle, delimiter=','):
        myArray.append(row)

我可以成功打印数组中的各个行……

print myArray[0]    # Works fine!  Prints header row.
print myArray[1]    # Works fine!  Prints first data row.

但是,当我尝试遍历从 CSV 文件创建的数组以提取每一行时,我遇到了失败。 for循环代码如下...

for idx, row in myArray:  # <--- This where the error message points to
    print 'Index = ' + str(idx)
    print row

我得到的错误信息是:

Traceback (most recent call last):
    File “myScript.py”, line 155, in (module)
        For idx, row in myArray:
ValueError: too many values to unpack

我的问题:究竟为什么会发生这种情况以及解决此问题的最佳方法是什么?

【问题讨论】:

【参考方案1】:

您遇到的错误意味着变量名多于实际值。

示例:

lst = [1,2]
a,b = lst # <-- this is ok

a,b,c = lst # error 

所以如果你需要idx,你可以尝试使用enumerate,这样每次迭代都会产生两个值

for idx, row in enumerate(myArray): 
    print 'Index = ' + str(idx)
    print row

如果你想改变元素

res = []
for idx, row in enumerate(myArray): 
  print 'Index = ' + str(idx)
  print row
  #do change
  res.append(changed_row)

【讨论】:

不枚举行使其完全不可变/不可更改?以后如何更改行中的值?例如,如果我想稍后替换行中的字符串怎么办? @InformationTechnology docs.python.org/2/library/functions.html#enumerate 这是文档。它不会改变任何东西。 @InformationTechnology btw,如果你想在迭代过程中改变元素,你最好创建另一个列表 @galaxyan 没有什么能阻止你改变一个列表。您通常要避免的是在迭代同一序列时添加/删除序列,因为它会弄乱迭代器......【参考方案2】:

列表的行为与任何其他序列 wrt/ 迭代没有什么不同:你只得到项目,而不是索引(就像在迭代 csv.reader 时你只得到行,而不是索引)。

如果你想同时拥有索引和项目,你可以使用enumerate():

for index, item in enumerate(somelist):
    print("item at  is ".format(index, item))

更新:

因为它是枚举的,“item”不是不可变的吗?如果我想稍后更改它的数据怎么办(例如替换文本字符串)

迭代不会使任何东西或多或少可变。一个对象要么是可变的(在for 循环体中改变它的工作方式与在循环外相同),要么它不是,句号。

您似乎对变异和重新绑定之间的区别感到困惑。这是一个包含可变对象列表的示例:

>>> data = [dict(a=i) for i in xrange(3)]
>>> data
['a': 0, 'a': 1, 'a': 2]
>>> for item in data:
...     item["b"] = item["a"] + 42
... 
>>> data
['a': 0, 'b': 42, 'a': 1, 'b': 43, 'a': 2, 'b': 44]

如您所见,这些项目是完全可变的..

现在您不能使用不可变对象列表来执行此操作,这不是因为for 循环(您是否使用enunerate 在这里无关紧要),而是因为不可变对象是不可变的。让我们首先在 for 循环之外检查一下:

>>> s = "foo 1"
>>> s.replace("1", "2")
'foo 2'
>>> s
'foo 1'

如您所见,str.replace() 返回一个新字符串并保持原始字符串不变(当然 - 字符串是不可变的)。如果你想让s 变成“foo 2”,你必须重新绑定 s 使它指向另一个 字符串:

>>> s
'foo 1'
>>> id(s)
139792880514032
>>> s = s.replace("1", "2")
>>> s
'foo 2'
>>> id(s)
139792880474080

请注意,重新绑定变量不会影响指向同一对象的其他变量:

>>> s1 = "aaa"
>>> id(s1)
139792880524584
>>> s2 = "bbb"
>>> id(s2)
139792880522104
>>> s1 = "aaa"
>>> s1
'aaa'
>>> id(s1)
139792880524584
>>> s2 = s1
>>> s2
'aaa'
>>> id(s2)
139792880524584
>>> s2 is s1
True
>>> # now let's rebind s1:    
>>> s1 = "bbb"
>>> s1
'bbb'
>>> id(s1)
139792880522104
>>> s2
'aaa'
>>> id(s2)
139792880524584
>>> s2 is s1
False
>>> 

所以重新绑定迭代变量(我们上面的 sn-ps 中的item)在技术上是有效的(这个变量是反弹),但这不会影响列表或您在上面迭代的任何内容(就像重新绑定 s1 不会'影响s2):

>>> data = ["aaa", "bbb", "ccc"]
>>> for item in data:
...     print "item before : ".format(item)
...     item = 42
...     print "item after : ".format(item)
...     print "data : ".format(data)
... 
item before : aaa
item after : 42
data : ['aaa', 'bbb', 'ccc']
item before : bbb
item after : 42
data : ['aaa', 'bbb', 'ccc']
item before : ccc
item after : 42
data : ['aaa', 'bbb', 'ccc']

因此,如果您有一个字符串列表并且想要更新该列表,您必须改变列表本身 - 这也需要匹配索引,您可以使用 enumerate

>>> data = ["aaa", "bbb", "ccc"]
>>> for index, item in enumerate(data):
...     data[index] = item.upper()
... 
>>> data
['AAA', 'BBB', 'CCC']

请注意,这里我们不是重新绑定迭代变量,而是改变data 列表本身。它的工作原理与没有 for 循环的情况相同:

>>> data = ["aaa", "bbb", "ccc"]
>>> item = data[0]
>>> item
'aaa'
>>> item = "AAA"
>>> item
'AAA'
>>> data
['aaa', 'bbb', 'ccc']

对比:

>>> data = ["aaa", "bbb", "ccc"]
>>> data[0] = "AAA"
>>> data
['AAA', 'bbb', 'ccc']
>>> 

【讨论】:

因为是枚举的,“item”不是不可变的吗?如果我想稍后更改它的数据(例如替换文本字符串)怎么办? @InformationTechnology:尝试提供的解决方案,看看它是否使item 不可变。实验结果如何? 很棒的解释。谢谢。

以上是关于创建数组后,如何正确遍历 CSV 文件中的行数组?的主要内容,如果未能解决你的问题,请参考以下文章

BASH - 从 csv 文件的行创建数组,其中第一个条目是数组名称

为啥 sscanf() 不将 CSV 文件中的行读入数组?

php 使用SplFileObject读取CSV文件。从CSV文件定义标题或管理标题行。返回数组中的行,标题值为

如何获取正在循环的数组的行号?

在laravel-excel中循环遍历数组中的数组

取消选择数据表行后如何正确删除数组中的索引或值?