在python中,如何删除列表中满足特定条件的最左/最右元素?

在python中,如何删除列表中满足特定条件的最左/最右元素?,python,Python,我有一个如下列表: ['a'、'b'、'c'、''、''、''] 这是解析“脏”csv文件的结果。我现在想去掉右边的空列。我不能只用计数,因为长度是可变的。我也不能只使用简单的筛选,因为还有一些行是这样的: ['a1'、''c1'、''''、'''.'] 因此,我必须保留右边的空列而不是。有没有一种惯用的方法可以做到这一点?我希望像“removeWhile”这样的函数可以应用到反向列表中 到目前为止,我提出的最好的建议如下: def filterRow(row): row.reverse

我有一个如下列表:

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

也许是这样的

>>> 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']
如果出于某种原因,您不想在适当的位置执行此操作,请按以下方式执行:

def filterRow(row):
    row = list(row)
    while row[-1] == "":
        row.pop()
    return row
从列表末尾弹出非常快,虽然计算最后一个索引和执行切片可能会稍微快一点,但这也会导致代码更长、更复杂、更难读取。因此,现在就使用可读版本,只考虑一旦确定它是实践中的一个重要瓶颈就改变它。

为了使函数更加直观,为什么不将其称为
rstrip
而不是
filterRow
,因为它与
str.rstrip
对字符串的作用几乎相同?

虽然@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']

类似于此,无需创建任何新字符串、列表或使用反转:

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

下面是一个使用单个切片的简洁实现:

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]是一个生成器表达式,它从右向左遍历索引,跳过空索引,则索引中的i为i

  • next(iterable)
    获取生成表达式的第一个元素。应用于上述生成器表达式,它返回最右边非空元素的索引

  • del row[rightmest+1:][/code>删除行末尾的所有空元素。(或者,
    return row[:rightmest+1]
    返回最右边非空元素之前的所有元素。)


很晚了,但就让它在这里吧:

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)              # []
def strip(xs,谓词=lambda x:not x):
“”“给定一个序列,请删除与谓词匹配的前导/尾随项。”“”
m=[bool(谓词(x))表示xs中的x]
尝试:
a=m.索引(假)
b=m[:-1]。索引(False)
返回xs[a:len(xs)-b]
除值错误外:
返回[]
打印条(['','',1,2',,3,4,0,无,'','')#[1,2',,3,4]
打印条([1,2,10,20,3,30,5,6],λx:x<10)#[10,20,3,30]
打印条([10,20,3,30],λx:x<10)#[10,20,3,30]
打印条([1,2,3],λx:x<10)#[]

+1,非常优雅。演示了切片方法,但索引计算很长,很难理解,或者两者都很难理解。+1,但请注意,当所有列都为空时,这会中断。@root将条件更改为
,而行和行[-1]==“”
,但将这样一个优雅的解决方案弄得乱七八糟将是一件憾事——至少我的直觉是OP的行从来都不是空的。这个解决方案的问题是它假定了一个固定的CSV语法。尽管名称不同,CSV支持许多不同的字段分隔符(至少在欧洲版本中,Excel默认为
,因为在大多数欧洲语言中,
是十进制分隔符)。然后是引号,它可以创建不同的方式来表示空列。除非您自己生成输入CSV,否则处理它应该留给CSV读取器。@user4815162342-这只是一个玩具示例。无论如何,您仍然可以将
CSV.reader
与类似的生成器一起使用:
CSV.reader(line.rstrip(',\n'))对于f中的行)
-您仍然需要指定分隔符,但通常在读取文件之前您知道格式。但这正是问题所在-您通常不知道将遇到的CSV方言,
CSV
模块会自动为您检测它。@user4815162342-当您使用嗅探器时,您的意思是什么?我几乎从未见过使用过它…但您是正确的t、 如果你想使用自动检测,这是不合适的。否则我会说它是更有效和可读的。
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)              # []