5

我有一个看起来像这样的列表:

['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]
4

6 回答 6

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

于 2013-04-20T12:11:44.250 回答
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']
于 2013-04-20T12:13:17.140 回答
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]返回所有元素,包括最右边的非空元素。)

于 2013-04-20T12:16:40.483 回答
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']
于 2013-04-20T12:10:51.777 回答
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]: []
于 2013-04-20T12:13:46.960 回答
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)              # []
于 2013-04-20T13:33:58.100 回答