aberger
aberger

Reputation: 2417

Get complement (opposite) of list slice

Is there syntax to get the elements of a list not within a given slice? Given the slice [1:4] it's easy to get those elements:

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

If I want the rest of the list I can do:

>>> l[:1] + l[4:]
[1, 5]

Is there an even more succinct way to do this? I realize that I may be being too needy because this is already very concise.

EDIT: I do not think that this is a duplicate of Invert slice in python because I do not wish to modify my original list.

Upvotes: 5

Views: 3317

Answers (5)

norok2
norok2

Reputation: 26956

I was looking for some solution for this problem that would allow for proper handling of the step parameter as well. None of the proposed solution was really viable, so I ended up writing my own:

def complement_slice(items, slice_):
    to_exclude = set(range(len(items))[slice_])
    step = slice_.step if slice_.step else 1
    result = [
        item for i, item in enumerate(items) if i not in to_exclude]
    if step > 0:
        return result
    else:
        return result[::-1]

ll = [x + 1 for x in range(5)]
# [1, 2, 3, 4, 5]
sl = slice(1, 4)

ll[sl]
# [2, 3, 4]

complement_slice(ll, sl)
# [1, 5]

To the best of my knowledge, it does handle all the corner cases as well, including steps, both positive and negative, as well as repeating values.

I wanted to write it as a generator, but I got annoyed by checking all corner cases for positive/negative/None values for all parameters. In principle, that is possible, of course.

Upvotes: 0

[x for i, x in enumerate(l) if i not in range(1, 4)]

Which is less concise. So the answer to your question is no, you can't do it more concisely.

Upvotes: 0

SHIVAM JINDAL
SHIVAM JINDAL

Reputation: 2984

You can use list comprehension with loop

l = [i for i in l if i not in l[1:4]]

Upvotes: -2

Jared Goguen
Jared Goguen

Reputation: 9008

Clearly the best solution to create a class to encapsulate some magical behavior that occurs when you use 'c' as the step value. Clearly.

class SuperList(list):
    def __getitem__(self, val):
        if type(val) is slice and val.step == 'c':
            copy = self[:]
            copy[val.start:val.stop] = []
            return copy

        return super(SuperList, self).__getitem__(val)


l = SuperList([1,2,3,4,5])
print l[1:4:'c'] # [1, 5]

Upvotes: 0

Tyler
Tyler

Reputation: 91

If you want to modify the list in-place, you can delete the slice:

>>> l = [1, 2, 3, 4, 5]
>>> del l[1:4]
>>> l
[1, 5]

Otherwise your originally suggestion would be the most succinct way. There isn't a way to get the opposite of a list slice using a single slice statement.

Upvotes: 3

Related Questions