Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Python slicing be used to skip one specific element by index?

Tags:

python

Suppose I am writing a recursive function where I want to pass a list to a function with a single element missing, as part of a loop. Here is one possible solution:

def Foo(input):
    if len(input) == 0: return
    for j in input:
       t = input[:]
       t.remove(j)
       Foo(t)

Is there a way to abuse the slice operator to pass the list minus the element j without explicitly copying the list and removing the item from it?

like image 798
merlin2011 Avatar asked Mar 09 '14 08:03

merlin2011


People also ask

How do you slice a specific index in Python?

To extract elements with specific indices from a Python list, use slicing list[start:stop:step] . If you cannot use slicing because there's no pattern in the indices you want to access, use the list comprehension statement [lst[i] for i in indices] , assuming your indices are stored in the variable indices .

How do you skip slice in Python?

String Slicing: How to Skip Last Character You can use negative indices as start or stop arguments of the string slicing operation. In this case, Python starts counting from the right. For instance, the negative index -1 points to the last character in the string, the index -2 points to the second last and so on.

What does [- 1 :] mean in Python?

Python also allows you to index from the end of the list using a negative number, where [-1] returns the last element. This is super-useful since it means you don't have to programmatically find out the length of the iterable in order to work with elements at the end of it.

What is slicing in Python?

Slicing is the extraction of a part of a string, list, or tuple. It enables users to access the specific range of elements by mentioning their indices. Note: The search will start at index one (included) and ends at index six (not included). The following image shows some examples of slicing in a string and tuple:

What is the slicing seq [start stop] in Python?

The slicing seq [start:stop] returns the elements starting at the index start up to the index stop - 1. Therefore, it’s easier to visualize that the indexes are between the elements when you slice the sequence: Everything in Python is an object including the slice. A slice is actually an object of the slice type. When you use the slicing notation:

How to SLIC a list in Python?

Consider a python list, In-order to access a range of elements in a list, you need to slice a list. One way to do this is to use the simple slicing operator i.e. colon(:) With this operator, one can specify where to start the slicing, where to end, and specify the step. List slicing returns a new list from the existing list. Syntax:

What is the use of slice insertion and deletion in Python?

Slice insertion in Python Users can insert items into a list without replacing other elements. 2. Slice deletion in Python Users can delete multiple items out of the data structure by using a del statement. Note: Tuple object does not support item deletion. Looking forward to make a move to programming?


3 Answers

What about this?

for i in range(len(list_)):
    Foo(list_[:i] + list_[i+1:])

You are stilling copying items, though you ignore the element at index i while copying.

BTW, you can always try to avoid overriding built-in names like list by appending underscores.

like image 141
satoru Avatar answered Oct 22 '22 06:10

satoru


If your lists are small, I recommend using the approach in the answer from @satoru.

If your lists are very large, and you want to avoid the "churn" of creating and deleting list instances, how about using a generator?

import itertools as it
def skip_i(seq, i):
    return it.chain(it.islice(seq, 0, i), it.islice(seq, i+1, None))

This pushes the work of skipping the i'th element down into the C guts of itertools, so this should be faster than writing the equivalent in pure Python.

To do it in pure Python I would suggest writing a generator like this:

def gen_skip_i(seq, i):
    for j, x in enumerate(seq):
        if i != j:
            yield x

EDIT: Here's an improved version of my answer, thanks to @Blckknght in comments below.

import itertools as it
def skip_i(iterable, i):
    itr = iter(iterable)
    return it.chain(it.islice(itr, 0, i), it.islice(itr, 1, None))

This is a big improvement over my original answer. My original answer only worked properly on indexable things like lists, but this will work correctly for any iterable, including iterators! It makes an explicit iterator from the iterable, then (in a "chain") pulls the first i values, and skips only a single value before pulling all remaining values.

Thank you very much @Blckknght!

like image 30
steveha Avatar answered Oct 22 '22 07:10

steveha


Here is a code equivalent to satoru's, but is faster, as it makes one copy of the list per iteration instead of two:

before = []
after = list_[:]

for x in range(0, len(list_)):
    v = after.pop(0)
    Foo(before + after)
    before.append(v)

(11ms instead of 18ms on my computer, for a list generated with list(range(1000)))

like image 28
Valentin Lorentz Avatar answered Oct 22 '22 07:10

Valentin Lorentz