如何删除列表中满足某个标准的最左侧/最右侧元素?

时间:2013-04-20 12:05:17

标签: python

我有一个如下所示的列表:

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

6 个答案:

答案 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)              # []