Reverse a slice of an array in-place [duplicate] - python

This question already has answers here:
How do I reverse a part (slice) of a list in Python?
(8 answers)
Reverse part of an array using NumPy
(3 answers)
Closed 3 years ago.
What is the best (fastest/most pythonic) way to reverse a part of an array in-place?
E.g.,
def reverse_loop(l,a,b):
while a < b:
l[a],l[b] = l[b],l[a]
a += 1
b -= 1
now after
l = list(range(10))
reverse_loop(l,2,6)
l is [0, 1, 6, 5, 4, 3, 2, 7, 8, 9] as desired.
Alas, looping in Python is inefficient, so a better way is needed, e.g.,
def reverse_slice(l,a,b):
l[a:b+1] = l[b:a-1:-1]
and reverse_slice(l,2,6) restores l to its original value.
Alas, this does not work for the border cases: reverse_slice(l,0,6)
truncates l to [7, 8, 9] because l[a:-1:-1] should be l[a::-1].
So, what is The Right Way?

How about this?
def reverse_slice(l, a, b):
l[a:b] = l[a:b][::-1]
l = list(range(10))
reverse_slice(l, 0, 6) # excludes l[6]
print(l)
Output:
[5, 4, 3, 2, 1, 0, 6, 7, 8, 9]
An alternative with the inbuilt function reversed:
def reverse_func(l, a, b):
l[a:b] = reversed(l[a:b])
In my tests, slicing is faster than using reversed by a factor of 1.2x-1.5x.

[6::-1] can be written as [6:None:-1]:
def reverse_slice(l,a,b):
a1 = None if a==0 else a-1
l[a:b+1] = l[b:a1:-1]
In [164]: y=x.copy(); reverse_slice(y,1,6);y
Out[164]: [0, 6, 5, 4, 3, 2, 1, 7, 8, 9]
In [165]: y=x.copy(); reverse_slice(y,0,6);y
Out[165]: [6, 5, 4, 3, 2, 1, 0, 7, 8, 9]

Related

How to split a numpy array based on a tuple content? [duplicate]

This question already has an answer here:
Create index list for np.split from the list that already has number for each section
(1 answer)
Closed 3 years ago.
Let's say I've got an array [0, 1, 2, 3, 4, 5, 6, 7] and a tuple: (3, 3, 2).
I'm looking for a way to split my array to 3 array based on my tuple data:
[0, 1, 2]
[3, 4, 5]
[6, 7]
I can write a simple code like this to get what I want, however I'm looking for a correct and pythonic way to do this:
I used lists for simplicity.
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = []
for j in range(i):
lst.append(a[pointer])
pointer += 1
print(lst)
Or this one:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
pointer = 0
for i in b:
lst = a[pointer:pointer+i]
pointer += i
print(lst)
Results:
[0, 1, 2]
[3, 4, 5]
[6, 7]
you can use the split method of numpy
import numpy as np
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
c = np.split(a, np.cumsum(b)[:-1])
for r in c:
print(r)
np.split(a, b) splits a by the indices in b along a given axis(0 by default).
If you don't want to modify your input list, you can use an iterator and the itertools module.
>>> from itertools import islice
>>> a = [0, 1, 2, 3, 4, 5, 6, 7]
>>> b = (3, 3, 2)
>>> i = iter(a)
>>> [list(islice(i, x)) for x in b]
[[0, 1, 2], [3, 4, 5], [6, 7]]
In the first step you create an iterator, which starts at the first element of a. Then you iterate in a list comprehension over your numbers in b and in each step you pull accordingly many elements from the iterator and store them in your result list.
One simpler way is this:
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
for ind in b:
print(a[:ind])
a = a[ind:]
It loops through slice sizes in b while shortening the original array every time. You can easily append the resulting slices as sublists if you need them for something else. It's almost like one of your solutions except it doesn't use any extra variables and iterates directly through elements of b.
Also, I wouldn't call variables a and b - surely not in this case where variables have clear meanings that you can express through their names. More meaningful names lessen bugs number and make code more clear, becomes a real difference with larger/more complex code. I'd call a at least in_list and b slices, but with more context this could be better.
The most "concise" syntax would be :
ex_array = [0, 1, 2, 3, 4, 5, 6, 7]
extuple = (3, 3, 2)
result = [ex_array[sum(extuple[:iii]):sum(extuple[:iii])+extuple[iii]] for iii in range(len(extuple))]
result would be a list of the expected sub-lists
Re-using the pairwise function from Compare two adjacent elements in same list, you could also:
from itertools import accumulate
from more_itertools import pairwise
a = [0, 1, 2, 3, 4, 5, 6, 7]
b = (3, 3, 2)
[a[slice(*s)] for s in pairwise(accumulate((0,)+b))]
That begin said, the np.split answer is probably faster (and easier to read).

Order list number from given number [duplicate]

This question already has answers here:
Efficient way to rotate a list in python
(27 answers)
Closed 6 years ago.
In detail, ex: I have a list weekday:
list_week_day = [0,2,4,5,6]
if today.weekday() = 3 , then order list_week_day = [4,5,6,0,2]
So, how to do that ???
new = old[n:] + old[:n]
You append the front part of the list to the back part. Can you finish after that hint? n is your weekday.
Could also try:
wday = 3
[(x + wday) % 7 for x in list_week_day]
# [3, 4, 5, 6, 0, 1, 2]
Did you try the following? I suspect it is not the most efficient way to get what you desire, but it certainly is a way to get it.
list_week_day[today.weekday() : ] + list_week_day[ : today.weekday()]
As suggested here, you can use numpy's roll command, choosing a suitable value to roll by:
>>> import numpy
>>> a=numpy.arange(1,10) #Generate some data
>>> numpy.roll(a,1)
array([9, 1, 2, 3, 4, 5, 6, 7, 8])
>>> numpy.roll(a,-1)
array([2, 3, 4, 5, 6, 7, 8, 9, 1])
>>> numpy.roll(a,5)
array([5, 6, 7, 8, 9, 1, 2, 3, 4])
>>> numpy.roll(a,9)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])

How to get the 1st, 3rd and 5th element from an array in Python? [duplicate]

This question already has answers here:
Compact way to assign values by slicing list in Python
(5 answers)
Closed 2 years ago.
Is there a fast way to get the 1st, 3rd and 5th element from an array in Python like a[0,2,4]? Thanks.
Using operator.itemgetter:
>>> lst = [1,2,3,4,5,6,7]
>>> import operator
>>> get135 = operator.itemgetter(0, 2, 4)
>>> get135(lst)
(1, 3, 5)
You could just do this, a simple method with no imports necessary:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> [a[i] for i in (0, 2, 4)]
[1, 3, 5]
Slicing is the simplest way to do this. You'll want to slice it with [0:5:2].
>>> range(100)[0:5:2]
[0, 2, 4]
This is the equivalent of saying "Starting from element 0, up to (but not including) element 5, give me every 2nd element."
You can use slicing to get this.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
d = a[0:5:2]
print d
[1, 3, 5]
If you want to generalize to every other entry you would use
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = a[::2]
print b
[1, 3, 5, 7, 9]
You can use ,
Slicing operation on list.
>>> a=[i for i in range(10)]
>>> a[::2]
Ouput:
[0, 2, 4, 6, 8]
perhaps:
[list[0], list[2], list[4]]

concatenating sublists python [duplicate]

This question already has answers here:
How do I make a flat list out of a list of lists?
(34 answers)
Closed 9 years ago.
I have one list like:
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
I want to create a function that takes a single list (see above) and concatenates all the sublists that are part of it into a single list.
n = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
nn = [ x for y in n for x in y]
>>> lst = [[1, 2, 3], [4, 5, 6, 7, 8, 9]]
>>> from itertools import chain
>>> list(chain.from_iterable(lst))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
For completeness, here is a very short way to write this
>>> sum(n, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
But although it is tempting, you shouldn't because it has quadratic performance. ie a new list is created as each term is added, and all the previous items will be copied over and over
It's ok to use list.extend though
reduce(lambda x,y: x.extend(y) or x, n, [])
You can also concatenate by doing simply:
print n[0]+n[1]
In general this would be:
def concatenate(list):
x=[]
for i in list:
x+=i
return x
But this is not particularly efficent, just quite straightforward for a beginner.

Iterating in a closed range [a, b] in python

I want to iterate over a closed range of integers [a, b] in python, ie. iterating from a to b including both a and b.
I know the following way of doing it:
for i in range(a, b+1):
do_something(i)
For iterating in the reverse direction (ie. in the order b, b-1, b-2, ..., a), I do the following:
for i in range(b, a-1, -1):
do_something(i)
I don't like this addition (b+1 in the example) and subtraction (a-1 in the example) to reach the closed end of the range. I find it less readable than the c/c++/Java counterpart (usage of <= in a loop).
Do you have something in python which can be used to iterate between the closed ranges without manual intervention of the boundaries?
It's a simple matter to define your own function and use it:
def closed_range(start, stop, step=1):
dir = 1 if (step > 0) else -1
return range(start, stop + dir, step):
In action:
>>> list(closed_range(1, 10))
0: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(closed_range(1, 10, 2))
1: [1, 3, 5, 7, 9]
>>> list(closed_range(1, 10, 3))
2: [1, 4, 7, 10]
>>> list(closed_range(10, 1, -1))
3: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(closed_range(10, 1, -2))
4: [10, 8, 6, 4, 2]
Save to a .py file in \PythonXX\Lib\site-packages and then you can import it for use elsewhere.

Categories

Resources