如何从列表中删除最后一个项目?

时间:2015-05-08 01:50:19

标签: python list

list.remove()函数用于在项目第一次出现在列表中时删除。是否有内置功能可以删除最后一次?例如,如果我有一个列表,请说:

X = ['sf', 'cc', 'ch', 'sc', 'sh', 'ch']

我希望从列表中删除最后一个'ch',是否有比我目前正在做的更好的方法,即:

X.reverse()
X.remove('ch')
X.reverse()

我很快就会担心被删除的项目可能不在列表中的情况。因此,在这种情况下不抛出错误的方法将是首选。谢谢!

7 个答案:

答案 0 :(得分:6)

if 'ch' in X:
    X.reverse()
    X.remove('ch')
    X.reverse()

最狡猾的方式是在try: except周围删除:

X.reverse()
try:
    X.remove('ch')
except:
    pass
X.reverse()

根据你对速度的评论,这两种方法都是O(N),因为x in listlist.reverse()都是O(N),所以它们之间并不多。如果您希望元素通常在那里,您可以使用try:catch保存x in list检查,但是如果您希望它通常不存在,则可以通过检查来保存2 reverse()首先是会员资格。

答案 1 :(得分:3)

你的代码完全没有问题。它很有效,很清楚为什么它起作用,很难出错或误解。

是的,你可以让它更快,但只能通过一个恒定的因素。 (您的算法会执行两个reverse,每个N步,一个removeN-1步,O(N)。并且由于您的数据没有排序或任何有助于我们更快地找到价值的东西,很明显,理想的算法也会O(N)。)并且以使其更复杂为代价。

明显可能更快的方法是从最后手动迭代直到我们找到一个值,然后删除该值。这也避免了必须处理ValueError。使用enumerate可能会有所帮助......但是正确使用它(不复制整个事情)可能会很棘手。

因此,我们将这些代码与您现有的代码进行比较,两者都包含在try / exceptif中:

def f_rev_ex(xs, s):
    xs.reverse()
    try:
        xs.remove(s)
    except ValueError:
        pass
    xs.reverse()

def f_rev_if(xs, s):
    if s in xs:
        xs.reverse()
        xs.remove(s)
        xs.reverse()

def f_for(xs, s):
    for i in range(len(xs)-1, -1, -1):
        if s == xs[i]:
            del xs[i]
            break

def f_enum(xs, s):
    for i, x in reversed(list(enumerate(xs))):
        if x == s:
            del xs[i]
            break

对于像你一样小的列表,测试甚至不值得运行,所以我发明了自己的随机数据(在现实生活中你必须知道你的数据):

In [58]: xs = [random.choice(string.ascii_lowercase) for _ in range(10000)]
In [59]: %timeit y = x[:]; f_rev_ex(y, 'a')
10000 loops, best of 3: 34.7 µs per loop
In [60]: %timeit y = x[:]; f_rev_if(y, 'a')
10000 loops, best of 3: 35.1 µs per loop
In [61]: %timeit y = x[:]; f_for(y, 'a')
10000 loops, best of 3: 26.6 µs per loop
In [62]: %timeit y = x[:]; f_enum(y, 'a')
1000 loops, best of 3: 604 µs per loop

嗯,最后一个不是一个好主意......但另一个比我们开始时快25%左右。因此,我们节省了整整9微秒,数据比实际数据大4个数量级。这取决于你是否值得用不那么易读,易于搞砸的代码。 (而且我不会在没有复制的情况下向你显示基于enumerate的实现,因为我弄错了。:P)

答案 2 :(得分:2)

生成反转列表,保留原始索引并删除您找到的第一个实例。

X = ['sf', 'cc', 'ch', 'sc', 'sh', 'ch']

print X

for i, e in reversed(list(enumerate(X))):
    if e == 'ch':
        del X[i]
        break

print X

如果它找不到字符串,则不会触及列表。

答案 3 :(得分:1)

首先,您可以使用if in语句检查项目是否在列表中。然后你可以反转列表并删除元素。

if "ch" in X:
    X.reverse()
    X.remove("ch")
    X.reverse()

答案 4 :(得分:1)

没有 reverse() 并且类似于上面的一个答案:

def RightRemove(alist, x):
    for i in range(len(alist), 0, -1): # from end to begin
        if alist[i-1] == x: # element x exists
            alist.pop(i-1) # remove it
            break # return

答案 5 :(得分:0)

又一个答案......

def remove_last_occurrence(lst, element):
    '''
    Removes the last occurrence of a given element in a list (modifies list in-place).

    :return bool:
        True if the element was found and False otherwise.
    '''
    for i, s in enumerate(reversed(lst)):
        if s == element:
            del lst[len(lst) - 1 - i]
            return True
    return False

答案 6 :(得分:0)

又一个..

def remove_last_occurrence_one_liner(lst, element):
    """
    Removes the last occurrence of a given element in a list (modifies list in-place).
    Raises same exception than lst.index(element) if element can not be found.
    """
    del lst[len(lst) - lst[::-1].index(element) - 1]

但是它没有击败abarnert的for循环

x = [random.choice(string.ascii_lowercase) for _ in range(10000)]
%timeit y = x[:]; f_rev_ex(y, 'a')
34.3 µs ± 219 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit y = x[:]; f_rev_if(y, 'a')
34.9 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit y = x[:]; f_for(y, 'a')
26.9 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit y = x[:]; f_enum(y, 'a')
699 µs ± 4.86 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit y = x[:]; remove_last_occurrence_one_liner(y, 'a')
49 µs ± 375 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)