Suggestion: PEP for popping slices from lists

  • Thread starter Neatu Ovidiu Gabriel
  • Start date
N

Neatu Ovidiu Gabriel

The list.pop(index) returns the element represented by the index and also reduces the list by removing that element. So it a short one liner for doing both things.
But when it comes for popping a slice of the list there is nothing similar for doing in that simple way.

If you want to remove a slice and also reduce the list you will have something like this:

a_list, a_slice = a_list[:size], a_list[size:]

or even worser if you try to do the same for something in the middle.

My proposal is the extension of list.pop for accepting a way for popping slices.

When doing this:

a_list.pop(i,j)

pop will return the slice [i,j] and remove it from the list.

For popping from an index to the end:

a_list.pop(i, len(a_list))

Or even emptying the whole list:

a_list.pop(0, len(a_list))


So this is it :)
 
P

Peter Otten

Neatu said:
The list.pop(index) returns the element represented by the index and also
reduces the list by removing that element. So it a short one liner for
doing both things. But when it comes for popping a slice of the list there
is nothing similar for doing in that simple way.

If you want to remove a slice and also reduce the list you will have
something like this:

a_list, a_slice = a_list[:size], a_list[size:]

or even worser if you try to do the same for something in the middle.

My proposal is the extension of list.pop for accepting a way for popping
slices.

When doing this:

a_list.pop(i,j)

pop will return the slice [i,j] and remove it from the list.

For popping from an index to the end:

a_list.pop(i, len(a_list))

Or even emptying the whole list:

a_list.pop(0, len(a_list))


So this is it :)

You'd use 'del' to remove a slice from a list. So:
.... x = slice(*indices)
.... result = items[x]
.... del items[x]
.... return result
....
items = range(10)
pop_slice(items, 3) [0, 1, 2]
items [3, 4, 5, 6, 7, 8, 9]
pop_slice(items, 3, 4) [6]
items [3, 4, 5, 7, 8, 9]
pop_slice(items, None, None, 2) [3, 5, 8]
items
[4, 7, 9]

But what's your use case?
Does it occur often enough that you cannot afford a two-liner like

result = items[start:stop]
del items[start:stop]

?
 
N

Neatu Ovidiu

Neatu Ovidiu Gabriel wrote:


The list.pop(index) returns the element represented by the index and also
reduces the list by removing that element. So it a short one liner for
doing both things. But when it comes for popping a slice of the list there
is nothing similar for doing in that simple way.

If you want to remove a slice and also reduce the list you will have
something like this:
a_list, a_slice = a_list[:size], a_list[size:]
or even worser if you try to do the same for something in the middle.
My proposal is the extension of list.pop for accepting a way for popping

When doing this:
a_list.pop(i,j)

pop will return the slice [i,j] and remove it from the list.
For popping from an index to the end:
a_list.pop(i, len(a_list))
Or even emptying the whole list:
a_list.pop(0, len(a_list))
So this is it :)



You'd use 'del' to remove a slice from a list. So:



... x = slice(*indices)

... result = items[x]

... del items[x]

... return result

...

[0, 1, 2]

[3, 4, 5, 6, 7, 8, 9]
pop_slice(items, 3, 4)
[6]

[3, 4, 5, 7, 8, 9]

[3, 5, 8]

[4, 7, 9]



But what's your use case?

Does it occur often enough that you cannot afford a two-liner like



result = items[start:stop]

del items[start:stop]



?

But what's your use case?

Does it occur often enough that you cannot afford a two-liner like
I think uses cases are plenty.
And how can I figure out how often it occurs? I don't have a hint, it remains an open question.

The issues I see so far with my proposal are:
- what you said, how often it is used, if it deserves a place
- maybe it should be a separate function like pop_slice to don't alter in anyway the behavior of good old pop
- it will rise some backwards compatibility issues

I just find it's a more pythonic way to deal with this situation. One short line instead of two or one long line is better. This shortness of typing is the core feature of Python so I think my proposal it's leap towards simplicity.
 
N

Nicholas Cole

I think uses cases are plenty.
The possible cases I can think of would be better served with list
comprehensions (what you seem to want is to create lists based on other
lists) - but maybe I'm missing something. Could we have one example?

N.
 
N

Neatu Ovidiu

I think uses cases are plenty.




The possible cases I can think of would be better served with list comprehensions (what you seem to want is to create lists based on other lists) - but maybe I'm missing something.  Could we have one example?



N.

This can be useful for doing all kinds of basic stuff. For example if you wanted to take 4 items of a list at at a time, do something with them and then update the list.

jobs = ['job1', 'job2', 'job3', 'job5', 'job6', 'job7', 'job8', 'job9', 'job10']
while jobs:
print jobs.pop_slice(0,4)
 
N

Neatu Ovidiu

I think uses cases are plenty.




The possible cases I can think of would be better served with list comprehensions (what you seem to want is to create lists based on other lists) - but maybe I'm missing something.  Could we have one example?



N.

This can be useful for doing all kinds of basic stuff. For example if you wanted to take 4 items of a list at at a time, do something with them and then update the list.

jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7', 'job8', 'job9', 'job10']
while jobs:
print(jobs.pop_slice(0,4))

should output

'job1', 'job2', 'job3', 'job4'
'job5', 'job6', 'job7', 'job8'
'job9', 'job10'
 
N

Neatu Ovidiu

I think uses cases are plenty.




The possible cases I can think of would be better served with list comprehensions (what you seem to want is to create lists based on other lists) - but maybe I'm missing something.  Could we have one example?



N.



This can be useful for doing all kinds of basic stuff. For example if youwanted to take 4 items of a list at at a time, do something with them and then update the list.



jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7', 'job8','job9', 'job10']

while jobs:

print(jobs.pop_slice(0,4))



should output



'job1', 'job2', 'job3', 'job4'

'job5', 'job6', 'job7', 'job8'

'job9', 'job10'

The idea "popped" in my mind while thinking about this question.
http://stackoverflow.com/questions/18121416/right-split-a-string-into-groups-of-3/18122084
I founded the list comprehensions solutions kind of cumbersome and thought that there should be a simple way to do this kind of stuff.
 
N

Nicholas Cole

comprehensions (what you seem to want is to create lists based on other
lists) - but maybe I'm missing something. Could we have one example?
This can be useful for doing all kinds of basic stuff. For example if
you wanted to take 4 items of a list at at a time, do something with them
and then update the list.
jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7', 'job8', 'job9', 'job10']

while jobs:

print(jobs.pop_slice(0,4))



should output



'job1', 'job2', 'job3', 'job4'

'job5', 'job6', 'job7', 'job8'

'job9', 'job10'

The idea "popped" in my mind while thinking about this question.

http://stackoverflow.com/questions/18121416/right-split-a-string-into-groups-of-3/18122084
I founded the list comprehensions solutions kind of cumbersome and thought
that there should be a simple way to do this kind of stuff.


Still seems a bit like a solution looking for a problem to me.

Why would you want to take four items at a time for a job from an arbitrary
part of a list? I agree splitting a string into groups of three looks a
bit cumbersome in the example you've given, but a generator could be
written quite easily, and would almost certainly be quicker than trying to
alter the list in place.

Best wishes,

N.
 
N

Neatu Ovidiu

But what's your use case?
Does it occur often enough that you cannot afford a two-liner like
I think uses cases are plenty.
The possible cases I can think of would be better served with list comprehensions (what you seem to want is to create lists based on other lists) - but maybe I'm missing something.  Could we have one example?

This can be useful for doing all kinds of basic stuff. For example if you wanted to take 4 items of a list at at a time, do something with them and then update the list.
jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7', 'job8', 'job9', 'job10']
while jobs:
    print(jobs.pop_slice(0,4))
should output
'job1', 'job2', 'job3', 'job4'
'job5', 'job6', 'job7', 'job8'
'job9', 'job10'



The idea "popped" in my mind while thinking about this question.

http://stackoverflow.com/questions/18121416/right-split-a-string-into-groups-of-3/18122084

I founded the list comprehensions solutions kind of cumbersome and thought that there should be a simple way to do this kind of stuff.

--

http://mail.python.org/mailman/listinfo/python-list





Still seems a bit like a solution looking for a problem to me.



Why would you want to take four items at a time for a job from an arbitrary part of a list?  I agree splitting a string into groups of three looksa bit cumbersome in the example you've given, but a generator could be written quite easily, and would almost certainly be quicker than trying to alter the list in place.



Best wishes,


N.

You are perfectly right. But I looked at it more like an improvement in thestyle of writing solutions and also a natural option because slices are highly present all over in python.
 
N

Nicholas Cole

comprehensions (what you seem to want is to create lists based on other
lists) - but maybe I'm missing something. Could we have one example?you wanted to take 4 items of a list at at a time, do something with them
and then update the list.
jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7',
'job8', 'job9', 'job10']
while jobs:





should output



'job1', 'job2', 'job3', 'job4'

'job5', 'job6', 'job7', 'job8'

'job9', 'job10'



The idea "popped" in my mind while thinking about this question.

http://stackoverflow.com/questions/18121416/right-split-a-string-into-groups-of-3/18122084

I founded the list comprehensions solutions kind of cumbersome and
thought that there should be a simple way to do this kind of stuff.
--

http://mail.python.org/mailman/listinfo/python-list





Still seems a bit like a solution looking for a problem to me.



Why would you want to take four items at a time for a job from an
arbitrary part of a list? I agree splitting a string into groups of three
looks a bit cumbersome in the example you've given, but a generator could
be written quite easily, and would almost certainly be quicker than trying
to alter the list in place.
Best wishes,


N.

You are perfectly right. But I looked at it more like an improvement in
the style of writing solutions and also a natural option because slices are
highly present all over in python.


I wasn't knocking it. I was just trying to think it through.
 
T

Terry Reedy

On 8/8/2013 7:44 AM, Neatu Ovidiu wrote:

Objection 1. People usually want to chunk sequences, not lists
specifically. We now try to add new features that work with iterators
and iterables generally, not just lists.
This can be useful for doing all kinds of basic stuff. For example if you wanted to take 4 items of a list at at a time, do something with them and then update the list.

jobs = ['job1', 'job2', 'job3', 'job4', 'job5', 'job6', 'job7', 'job8', 'job9', 'job10']
while jobs:
print(jobs.pop_slice(0,4))

should output

'job1', 'job2', 'job3', 'job4'
'job5', 'job6', 'job7', 'job8'
'job9', 'job10'

Objection 2. Usually when one wants to do this sort of thing, one wants
the list either be intact or empty at the end. Emptying it chunk by
chunk is worse than useless because it turns an O(n) process into an
O(n*n) process.

The same is true of destructively iterating through a list with .pop(0).
When I proposed the addition of .pop(), I meant it as the inverses of
..append and did not include the (optional) index parameter. It is seldom
used and usually only once, to remove a single leading item. The
addition of iterators, which occurred *after* the addition of .pop,
replaced some uses of .pop(0). For instance

first = mylist.pop(0) # O(N) operation
for item in mylist:
process(first, item)
del mylist

can, since 2.2, be written as

it = iter(mylist)
first = next(it) # O(1) operation
for item in it:
process(first, item)
del mylist

If .pop were being added today, I would argue against including the
index parameter.
 
J

Joshua Landau

If .pop were being added today, I would argue against including the index
parameter.

GASP! That's no fair!

1) When using pop you normally want to keep the mutability available,
so iter(mylist) is a no-go.
2) When using the index, it's often somewhere in the middle that
you're popping from
3) There's always deque for deques

That said you can always use blist which has O(log n) time complexity
for these pops. It's a hassle it's not stdlib :/.
 
T

Tim Chase

3) There's always deque for deques

Unless you have pre-2.4 code, in which case I'm glad .pop() was
included (but in this hypothetical world, we'd have a deque in
pre-2.4 too :-D

-tkc
 
T

Terry Reedy

GASP! That's no fair!

1) When using pop you normally want to keep the mutability available,
so iter(mylist) is a no-go.
2) When using the index, it's often somewhere in the middle that
you're popping from

I have never done that and I do not believe I have ever seen that. It
certainly is extremely rare in my experience. Removing an item *after*
looking at it is something different.

for i in range(len(mylist), -1, -1):
if pred(mylist): del mylist
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top