3

Let's say I have a list [1, 2, 3, 4, 2, 5]. Since 2 occurs twice, I want to remove the last occurrence of two. This is what I have done so far.

list.reverse()
list.remove(value) # value = 2
list.reverse()

But it seems that if I'm doing reversing twice for deleting a value, the algorithm complexity would be O(n). Is there any faster way of doing it?

Anh Pham
  • 695
  • 1
  • 6
  • 21

5 Answers5

1
if value in list:
    list.reverse()
    list.remove('ch')
    list.reverse()

The most pythonic way would be to do a try: except around remove:

list.reverse()
try:
    list.remove(value)
except:
    pass
list.reverse()

As per your comment on speed, both of these methods are O(N), as x in list and list.reverse() are both O(N), so there's not much between them. If you expect the element to usually be there, you can save the x in list check by using try: catch, however if you expect it to usually not be there, you can save the 2 reverse()s by checking for membership first.

Yogi
  • 609
  • 1
  • 8
  • 21
  • You are ignoring an exception. Use `try ... finally ...` instead. Or, better, don’t modify the list before removing the item. – Laurent LAPORTE Apr 07 '18 at 07:02
  • 3
    I won’t recommend this answer. It has two pitfalls: it redefines the builtin `list` function (really bad) and mask an exception (also bad). – Laurent LAPORTE Apr 07 '18 at 09:14
1

This approach removes one of the reversals at least:

def rremove(alist, x):
    alist.pop(len(alist) - alist[::-1].index(x) - 1)

my_list = [1, 2, 3, 4, 2, 5]

print(my_list)

rremove(my_list, 2)

print(my_list)

OUTPUT

[1, 2, 3, 4, 2, 5]
[1, 2, 3, 4, 5]

Just like list.remove(), it raises ValueError if the value is not present.

cdlane
  • 40,441
  • 5
  • 32
  • 81
1

You can create a dict , since dict can have unique values :

values=[1, 2, 3, 4, 2, 5]


no_repeat ={}
for i,j in enumerate(values):
    if j not in no_repeat:
        no_repeat[i]=j
    else:
        pass

print(no_repeat.values())

output

[1, 2, 3, 4, 5]
Aaditya Ura
  • 12,007
  • 7
  • 50
  • 88
1

IMO, the most efficient would be by iterating the list in reverse order, find the value 2, delete it and break the loop:

l = [1, 2, 3, 4, 2, 5]

for index, item in enumerate(reversed(l)):
    if item == 2:
        l.pop(len(l) - 1 - index)
        break

You get:

[1, 2, 3, 4, 5]

That way you don’t copy the list in memory nor loop twice.

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
  • @cdlane It does not. `reversed` returns a reverse iterator. `l[::-1]` creates a new list. – DylanYoung Nov 19 '19 at 21:49
  • @DylanYoung, I agree on this key difference but I think we're looking at two different efficiencies. This is more *space* efficient, as you note, but I'm guessing it's less *time* efficient as it uses a Python loop to walk an iterator instead of a **C** loop to walk a list. Maybe a close call given the time taken to copy the list. – cdlane Nov 19 '19 at 22:52
  • @cdlane Absolutely. Nothing wrong with either solution, just different :) – DylanYoung Nov 22 '19 at 18:44
0

This is a simpler function to remove an element's last occurrence in a list if found:

def right_remove(l: list, element: Any) -> None:
    try:
        index = l[::-1].index(element)
    except ValueError:
        return
    
    l.pop(len(l) - index - 1)
Ebram Shehata
  • 446
  • 5
  • 20