在Python中没有特定元素的快速返回列表的方法

时间:2013-04-01 06:29:25

标签: python

如果我有任意顺序的卡套装清单,如下:

suits = ["h", "c", "d", "s"]

我希望返回没有'c'

的列表
noclubs = ["h", "d", "s"]

有一种简单的方法吗?

9 个答案:

答案 0 :(得分:35)

suits = ["h","c", "d", "s"]

noclubs = [x for x in suits if x != "c"]

答案 1 :(得分:32)

>>> suits = ["h","c", "d", "s"]
>>> noclubs = list(suits)
>>> noclubs.remove("c")
>>> noclubs
['h', 'd', 's']

如果您不需要单独的noclubs

>>> suits = ["h","c", "d", "s"]
>>> suits.remove("c")

答案 2 :(得分:23)

此问题已得到解答,但我想解决使用列表理解比使用.remove()慢得多的评论。

我机器上的一些配置文件(使用Python 2.7.6)。

%%timeit
x = ['a', 'b', 'c', 'd']
y = x[:]  # fastest way to copy
y.remove('c')

1000000 loops, best of 3: 405 ns per loop

%%timeit
x = ['a', 'b', 'c', 'd']
y = list(x)  # not as fast copy
y.remove('c')

1000000 loops, best of 3: 689 ns per loop

%%timeit
x = ['a', 'b', 'c', 'd']
y = [n for n in x if n != 'c']  # list comprehension

1000000 loops, best of 3: 544 ns per loop

%%timeit
x = ['a', 'b', 'c', 'd']
i = x.index('c')
y = x[:i] + x[i + 1:]

1000000 loops, best of 3: 656 ns per loop

如果您使用最快的方式复制列表(这不是非常易读),您将比使用列表解析快36%。但是如果你使用list()类(这是更常见的和Pythonic)来复制列表,那么你将比使用列表理解慢26%。

真的,这一切都很快。我认为可以认为.remove()比列出列表理解技术更具可读性,但它并不一定更快,除非你有兴趣放弃复制中的可读性。

在这种情况下列表理解的一大优点是它更简洁(即如果你有一个函数是出于某种原因从给定列表中删除一个元素,它可以在一行中完成,而另一种方法需要3行。)有时候单行可以非常方便(虽然它们通常以一些可读性为代价)。此外,如果您实际上并不知道要删除的元素是否实际位于列表中,那么使用列表理解会很有用。虽然.remove()会抛出ValueError,但列表理解将按预期运行。

答案 3 :(得分:5)

如果订单重要,可以使用设置操作:

suits = ["h", "c", "d", "s"]
noclubs = list(set(suits) - set(["c"]))
# note no order guarantee, the following is the result here:
# noclubs -> ['h', 's', 'd']

答案 4 :(得分:4)

你可以使用过滤器(或来自itertools的ifilter)

suits = ["h","c", "d", "s"]
noclubs = filter(lambda i: i!='c', suits)

您也可以使用列表构建过滤

suits = ["h","c", "d", "s"]
noclubs = [ i for i in suits if i!='c' ]

答案 5 :(得分:3)

不使用for循环或lambda函数并保留顺序:

suits = ["h","c", "d", "s"]
noclubs = suits[:suits.index("c")]+suits[suits.index("c")+1:]

我知道在内部它仍然会使用循环,但至少你不必在外部使用它们。

答案 6 :(得分:1)

一种可能性是使用filter

>>> import operator
>>> import functools

>>> suits = ["h", "c", "d", "s"]

>>> # Python 3.x
>>> list(filter(functools.partial(operator.ne, 'c'), suits))
['h', 'd', 's']

>>> # Python 2.x
>>> filter(functools.partial(operator.ne, 'c'), suits)
['h', 'd', 's']

而不是partial也可以使用此__ne__的{​​{1}}方法:

'c'

然而,后一种方法不被认为是非常pythonic(通常你不应该使用特殊的方法 - 直接从双下划线开始),如果列表包含混合类型,它可以给出奇怪的结果但是它可能比>>> list(filter('c'.__ne__, suits)) ['h', 'd', 's'] 方法快一点。

partial

使用IPythons magic suits = ["h", "c", "d", "s"]*200 # more elements for more stable timings %timeit list(filter('c'.__ne__, suits)) # 164 µs ± 5.98 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) %timeit list(filter(functools.partial(operator.ne, 'c'), suits)) # 337 µs ± 13.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) %timeit list(filter(lambda x: x != 'c', suits)) # 410 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) %timeit [x for x in suits if x != "c"] 181 µs ± 465 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each) 命令测试Python 3.5.2。

答案 7 :(得分:0)

如果您想要删除特定的元素(而不仅仅是过滤),那么您需要接近以下内容:

noclubs = [x for i, x in enumerate(suits) if i != suits.index('c')]

如果确实你的问题与扑克牌有关,你也可以考虑在这里使用set更加语义正确。

答案 8 :(得分:0)

不幸的是,默认情况下,似乎没有像Python这样的内容。

有几个答案,但我虽然使用迭代器添加一个。如果可以接受改变,那将是最快的。如果您不想更改原始版本并且只想循环使用已过滤的集合,那么这应该非常快:

实现:

def without(iterable, remove_indices):
    """
    Returns an iterable for a collection or iterable, which returns all items except the specified indices.
    """
    if not hasattr(remove_indices, '__iter__'):
        remove_indices = {remove_indices}
    else:
        remove_indices = set(remove_indices)
    for k, item in enumerate(iterable):
        if k in remove_indices:
            continue
        yield item

用法:

li = list(range(5))
without(li, 3)             
# <generator object without at 0x7f6343b7c150>
list(without(li, (0, 2)))  
# [1, 3, 4]
list(without(li, 3))       
# [0, 1, 2, 4]

因此它是一个生成器 - 您需要调用list或其他东西使其永久化。

如果您只想删除单个索引,当然可以使用k == remove_index代替集合来加快速度。