2

With a list like

lst1 = [2, 3, 4, 5]

I'd like to easily insert a new number 1 at index [0], and at the same time drop the 5 at index [-1] so that I end up with:

[1, 2, 3, 4]

This can be done using:

lst1.insert(0,1)
lst1.pop()
print(lst1)

# output
# [1, 2, 3, 4]

But I'm a bit puzzled by the fact that there does not seem to exist a built-in method to do that directly. The closest thing I've found to a solution is assigning 1 to a list of its own, and then extending it with an indexed lst1 like this:

lst0=[1]
lst0.extend(lst1[:-1])

print(lst0)

# output:
[1, 2, 3, 4]

But somehow this feels a little backward, and it certainly isn't a one-liner. Is there a more pythonic way of doing this?


This is probably blatantly obvious to someone with a more fundamental Python knowledge than myself, and maybe it doesn't even justify a question in itself. But I'm experiencing an increasing curiosity about these things and would like to know if it's possible. And if not, then why?

Georgy
  • 12,464
  • 7
  • 65
  • 73
vestland
  • 55,229
  • 37
  • 187
  • 305
  • 5
    Why would two disjoint operations require a built-in method? But this will do exactly that in a single line `lst1 = [1]+lst1[:-1]` – Jongware Feb 26 '20 at 09:23
  • @usr2564301 Thank you for your suggestion. Would you consider writing it up as answer? I don't know the answer to your `disjoint operations` comment though. Working with a lot of time series and lagged periods of different lenghts, an operation like this would just seem like a very natural thing to perform on a list. – vestland Feb 26 '20 at 09:35
  • 1
    Conceptually you are looking for a "FIFO queue with limited size". And there are build-in implementations proivided. – AnsFourtyTwo Feb 26 '20 at 09:35
  • @SimonFink Yes, exactly a `FIFO queue with limited size"`. Which built-in implementations are you referring to? Something else than `collections.deque`? – vestland Feb 26 '20 at 09:37
  • 1
    `:)` I only consider these 2 disjoint operations *because* Python doesn't have built-in support for it. (An analog is Intel's math CPU: usually `sin` and `cos` *are* disjoint functions, but the CPU can actually calculate both in 'one go'.) A drawback of my assignment operation is that it creates a new list, though. – Jongware Feb 26 '20 at 09:41
  • `collections.deque` belongs to the Python STL, I don't know any other. – AnsFourtyTwo Feb 26 '20 at 09:41
  • @Georgy I sincerely don't think this question is a ducplicate of [Add entry to list and remove first one in Python](https://stackoverflow.com/questions/10155684/add-entry-to-list-and-remove-first-one-in-python) My own approach in my question would answer that question. In addition, the linked question asks for one thing in the title, and then the complete opposite in the body. Also, I'm specifically looking to do this in ***one line*** if possible. – vestland Feb 26 '20 at 13:38
  • @vestland It's true that your question is not an *exact* duplicate of the linked question. That question is a bit broader than yours, but several answers there cover your *one line* requirement perfectly. See, for example, [this answer](https://stackoverflow.com/a/10155753/7851470) which is the same as the one you accepted here. And about the unclear title. It happens all the time here. You are free to edit it so it would comply with the content. I've just done it myself. You may check if it's better now. – Georgy Feb 26 '20 at 15:16
  • @Georgy I've actually wondered a bit about that; should a question be closed if one among many answers to a *different* question provides a possible solution? I'm still not sure. – vestland Feb 26 '20 at 21:42
  • @vestland I don't think there is a strict rule or a guideline in the help center or on meta that would clarify all the edge cases of duplicate closures. IMHO, both questions, yours and the duplicate target are very closely related, and any answer that is posted or could be posted here would be applicable to the duplicate question as well, so the closure is justified. You could ask what other more seasoned SO users think about it, for example, [here](https://chat.stackoverflow.com/rooms/41570/so-close-vote-reviewers). – Georgy Feb 26 '20 at 22:19

4 Answers4

9

Use collections.deque

Ex:

import collections

l = collections.deque([2, 3, 4, 5], maxlen=4)    
print(l)
l.appendleft(1)    
print(l)

Output:

deque([2, 3, 4, 5], maxlen=4)
deque([1, 2, 3, 4], maxlen=4)
Rakesh
  • 81,458
  • 17
  • 76
  • 113
  • 1
    Not only is this the "one-liner", but it's also O(1) time compared to the original's O(n) time. – kaya3 Feb 26 '20 at 12:36
5

The list methods are in-place operations, which means they do not return the list itself, but the result of the operation. Because of this, there is not a one-line solution using the basic methods to both insert and pop at the same time.

You can either define a function and pass the list to it:

def insert_pop(lst, index, value):
    lst.insert(index, value)
    lst.pop()
    return lst

lst1 = [2, 3, 4, 5]
insert_pop(lst, 0, 1)
# returns:
[1, 2, 3, 4]

Or you can use a different data structure such as a collections.deque that only lets you have n elements inside. Adding a new element will pop one out other end.

James
  • 32,991
  • 4
  • 47
  • 70
2

you should use a queue data structure it's allow you to implement FIFO(first in first out) design. to create a queue in python:

```    
def queue(arr, queueSize, input):
    if(len(arr) <= queueSize - 1):
        arr.insert(0, input)
    else:
        arr.insert(0, input)
        arr.pop()
    return arr

print(queue([2,3,4,5] ,4 ,1))

for more read : https://www.geeksforgeeks.org/queue-data-structure/

sinammd
  • 122
  • 1
  • 1
  • 9
  • Yes, you should use a queue, but no, you should not use `.insert(0, ...)` to make a queue. This takes O(n) time. – kaya3 Feb 26 '20 at 12:37
0

One-liner using list comprehension.

def insert_pop(lst, insert_value, insert_idx, pop_idx):
    return [el 
            for x in (
                ([insert_value, v] if i == insert_idx and i != pop_idx else
                 [insert_value] if i == pop_idx else [v])
                for i, v in enumerate(lst) 
                if i != pop_idx or i == insert_idx) 
            for el in x]

lst1 = [2, 3, 4, 5]
print(insert_pop(lst1, 1, 0, 3))  # -> [1, 2, 3, 4]
print(insert_pop(lst1, 1, 3, 3))  # -> [2, 3, 4, 1]
Filip Młynarski
  • 3,534
  • 1
  • 10
  • 22