1

I have two numpy arrays:

Values = numpy.array([5, 6, 7, 8, 1, 2, 3, 14, 15, 16])
Lengths = numpy.array([4, 3, 3])   

What would be an efficient way to in numpy to reverse the order within the sublist to get this?

[8, 7, 6, 5, 3, 2, 1, 16, 15, 14]

I have tried for loop, but I believe there should be a more efficient way to do it using numpy functions.

jared
  • 4,165
  • 1
  • 8
  • 31
ElaineT
  • 13
  • 4

5 Answers5

1

You can do this by splitting the array (using np.split) at the desired indices, given by np.cumsum(Lengths), and then concatenating (using np.concatenate) them after each is reversed.

import numpy as np

Values = np.array([5, 6, 7, 8, 1, 2, 3, 14, 15, 16])
Lengths = np.array([4, 3, 3])

res = np.concatenate([split[::-1] for split in np.split(Values, np.cumsum(Lengths))])
print(res)

Output:

[ 8  7  6  5  3  2  1 16 15 14]
jared
  • 4,165
  • 1
  • 8
  • 31
1

For a vectorial solution, you can craft a sorter array with np.repeat, then use np.argsort to reorder your array

a = np.repeat(np.arange(len(Lengths)), Lengths)[::-1]
# array([2, 2, 2, 1, 1, 1, 0, 0, 0, 0])

out = Values[len(Values)-1-np.argsort(a)]

Output:

array([ 8,  7,  6,  5,  3,  2,  1, 16, 15, 14])

Intermediate:

len(Values)-1-np.argsort(a)
# array([3, 2, 1, 0, 6, 5, 4, 9, 8, 7])
mozway
  • 194,879
  • 13
  • 39
  • 75
0
import numpy as np

Values = np.array([5, 6, 7, 8, 1, 2, 3, 14, 15, 16])
Lengths = np.array([4, 3, 3])

splits = np.split(Values, np.cumsum(Lengths)[:-1]) #splits into 3 parts
reversed_list = [np.flip(split) for split in splits] #flip/reverse all the 3 parts

result = np.concatenate(reversed_list) # join all 3 parts
print(result)
vegan_meat
  • 878
  • 4
  • 10
0

According to this discussion, slicing is the among the fastest techniques, you can use for splitting. The following code uses only slicing and hence doesn't use any additional space or copying.

import numpy
Values = numpy.array([5, 6, 7, 8, 1, 2, 3, 14, 15, 16])
Lengths = numpy.array([4, 3, 3])  
start = 0
end = 0
for i in range(len(Lengths)):
  end = end + Lengths[i]
  if i == 0:  ## Isolate the first scenario as splitting doesn't accept -1 as second argument. [end:-1:step] is not valid
    Values[0:end] = Values[end-1::-1]
  else:
    Values[start:end] = Values[end-1:start-1:-1]
  start = end
  print(Values)
  
0

You can build a list of indexes that reverse the positions relatively to each chunk's last index. Then use that as an indirection on the values array.

import numpy as np

values  = np.array([5, 6, 7, 8, 1, 2, 3, 14, 15, 16])
lengths = np.array([4, 3, 3])

s      = np.cumsum(lengths) - 1
s[1:] += s[:-1] + 1
i      = np.repeat(s, lengths) - np.arange(values.size)


print(values[i])    
# [ 8  7  6  5  3  2  1 16 15 14]
Alain T.
  • 40,517
  • 4
  • 31
  • 51