63

如果我有一个任意顺序的卡片套装列表,如下所示:

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

我想返回一个没有'c'

noclubs = ["h", "d", "s"]

有没有一种简单的方法可以做到这一点?

4

9 回答 9

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

noclubs = [x for x in suits if x != "c"]
于 2013-04-01T06:30:19.867 回答
55
>>> suits = ["h","c", "d", "s"]
>>> noclubs = list(suits)
>>> noclubs.remove("c")
>>> noclubs
['h', 'd', 's']

如果您不需要单独的noclubs

>>> suits = ["h","c", "d", "s"]
>>> suits.remove("c")
于 2013-04-01T06:30:35.480 回答
36

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

我机器上的一些配置文件(使用 Python 3.6.9的笔记本)。

x = ['a', 'b', 'c', 'd']

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

1000000 loops, best of 3: 203 ns per loop

%%timeit
y = list(x)  # not as fast copy
y.remove('c')

1000000 loops, best of 3: 274 ns per loop

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

1000000 loops, best of 3: 362 ns per loop

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

1000000 loops, best of 3: 375 ns per loop

如果你使用最快的方法来复制一个列表(这不是很可读),你将比使用列表理解快 45%。但是,如果您使用list()类(更常见且 Pythonic)来复制列表,那么您将比使用列表理解慢 25%。

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

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

于 2014-11-11T22:32:04.667 回答
8

您可以使用过滤器(或来自 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' ]
于 2013-04-01T11:34:04.207 回答
6

如果顺序无关紧要,可以使用集合操作:

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']
于 2013-04-01T06:58:49.217 回答
4

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

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

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

于 2015-09-12T00:03:12.943 回答
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__方法'c'

>>> list(filter('c'.__ne__, suits))
['h', 'd', 's']

但是,后一种方法不被认为是非常 Pythonic(通常您不应该直接使用特殊方法 - 以双下划线开头),如果列表包含混合类型,它可能会产生奇怪的结果,但它可能比该partial方法快一点。

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 使用 IPython 的魔法%timeit命令进行了测试。

于 2017-08-06T19:53:53.927 回答
0

如果要删除特定元素(而不是仅过滤)很重要,则需要接近以下内容:

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

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

于 2013-04-01T06:46:59.070 回答
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而不是集合来使其更快。

于 2016-10-12T16:22:20.037 回答