我有一个如下所示的列表:
['a', 'b', 'c', '', '', '']
这是解析'脏'csv文件的结果。我现在想要摆脱右边的空列。我不能只使用计数,因为长度是可变的。我也不能只使用简单的过滤,因为还有一些行如下:
['a1', '', 'c1', '', '']
所以我必须保留最右边不的空列。这是否有惯用的方法?我希望有一些类似“removeWhile”的功能,我可以在反向列表中应用。
到目前为止,我想出的最好成绩如下:
def filterRow(row):
row.reverse()
blanks = 0
for x in row:
if x == '':
blanks += 1
else:
break
row.reverse()
return row[0:-blanks]
答案 0 :(得分:9)
def filterRow(row):
while row[-1] == "":
row.pop()
如果您因某些原因不想就地进行此操作,请改为:
def filterRow(row):
row = list(row)
while row[-1] == "":
row.pop()
return row
弹出列表的末尾非常快,虽然可能计算最后一个索引并做一个切片的速度稍快,但它也会导致更长,更复杂,更难阅读代码。因此,暂时使用可读版本,并且只有在确定它是实践中的重大瓶颈时才考虑更改它。
为了使该功能更加直观,为什么不将其称为rstrip
而不是filterRow
,因为它与str.rstrip
对字符串的作用几乎相同?
答案 1 :(得分:3)
虽然 @Lauritz V. Thaulow 对你的问题有最清晰的灵魂,但我想你可能会问错误的问题。相反,您应该在读取csv时删除空列,而不是在将其转换为列表之后。然后一个简单的line.rstrip(', \n')
应该这样做。
In [1]: lst = ['a1', '', 'c1', '', '']
In [2]: def remove_while(lst):
...: return ','.join(lst).rstrip(', ').split(',')
In [3]: remove_while(['a1', '', 'c1', '', ''])
Out[3]: ['a1', '', 'c1']
所以你可以:
with open('test.csv') as f:
for line in f:
print line.rstrip(', \n').split(',')
#['a1', '', 'c1']
#['a', 'b', 'c']
答案 2 :(得分:2)
也许是这样的?
>>> l = ['a', 'b', 'c', '', '', '']
# iterate through the list in reverse...
>>> for v in l[::-1]:
# when we encounter an element that's not empty, exit the loop
... if v:
... break
# otherwise pop the last element off the end of the list
... l.pop()
>>> l
['a', 'b', 'c']
答案 3 :(得分:2)
以下是使用单个切片的简洁实现:
def filterRow(row):
rightmost = next(i for i in reversed(xrange(len(row))) if row[i])
del row[rightmost + 1:]
# or, non-destructively: return row[:rightmost + 1]
说明:
reversed(xrange(len(row))
以相反的顺序生成列表索引;与`xrange(len(row) - 1,-1,-1)相同,但更具可读性。
i for i in INDICES if row[i]
是一个生成器表达式,它从右到左迭代索引,跳过空索引。
next(iterable)
获取生成的表达式的第一个元素。应用于上面的生成器表达式,它返回最右边非空元素的索引。
del row[rightmost + 1:]
删除行末尾的所有空元素。 (或者,return row[:rightmost + 1]
返回所有元素,包括最右边的非空元素。)
答案 4 :(得分:1)
像这样的东西,没有创建任何新的字符串,列表或使用反转:
In [138]: def remove_while(lis):
.....: le=len(lis)
.....: ind=0
.....: for i in xrange(le-1,-1,-1):
.....: if lis[i]!="":
.....: break
.....: else:
.....: ind+=1
.....: del lis[-ind:]
.....: return lis
.....:
In [139]: remove_while(['a', 'b', 'c', '', '', ''])
Out[139]: ['a', 'b', 'c']
In [140]: remove_while(['a1', '', 'c1', '', ''])
Out[140]: ['a1', '', 'c1']
In [141]: remove_while(['', '', '', '', ''])
Out[141]: []
答案 5 :(得分:0)
迟到了,但让它在这里:
def strip(xs, predicate=lambda x: not x):
"""Given a sequence, remove leading/trailing items that match the predicate."""
m = [bool(predicate(x)) for x in xs]
try:
a = m.index(False)
b = m[::-1].index(False)
return xs[a:len(xs)-b]
except ValueError:
return []
print strip(['','',1,2,'',3,4,0,None,'','']) # [1, 2, '', 3, 4]
print strip([1,2,10,20,3,30,5,6], lambda x: x < 10) # [10, 20, 3, 30]
print strip([10,20,3,30], lambda x: x < 10) # [10, 20, 3, 30]
print strip([1,2,3], lambda x: x < 10) # []