I am running a selection sort function in Python that works with numpy arrays instead of lists (so I can't use .pop for this, I don't think).
The function is:
def selectionSort(arr):
newArr = []
for i in range(len(arr)):
smallest = findSmallest(arr)
newArr.append((smallest))
arr = arr[(arr > smallest)]
return newArr
I want that "arr = arr[(arr > smallest)] which obviously doesn't work, to remove the smallest value (or, the value appended to newArr i.e the same value) from the passed array in the same way that .pop would do with a list.
I've tried things along these lines:
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
index = [2, 3, 6]
new_a = np.delete(a, index)
But couldn't get it to work. At the end of the day, I need to get something in the format of:
arr = randint(0,10,20)
to return an array sorted in ascending order. All I can manage is returning the smallest values repeated.
Thanks for any help
Try
arr = arr[np.where(arr > smallest)]
You may try:
arr = arr[ arr != np.min(a)]
This way you'll take from arr all the elements except the smallest one and reassign them to arr.
Your algorithm is almost correct. Indeed, it works if there are no duplicate values in arr:
import numpy as np
def selectionSort(arr):
newArr = []
for i in range(len(arr)):
smallest = findSmallest(arr)
newArr.append((smallest))
arr = arr[(arr > smallest)]
return newArr
findSmallest = np.min
# no duplicate values
auniq = np.random.choice(np.arange(20), (10,), replace=False)
print(auniq)
print(selectionSort(auniq))
Sample run:
[ 0 1 7 4 10 14 13 16 9 12]
[0, 1, 4, 7, 9, 10, 12, 13, 14, 16]
If there are duplicates it will crash because upon removing a minimum with duplicates the duplicates will be removed as well and that throws off the logic of the loop.
# duplicate values
adupl = np.random.randint(0, 9, (10,))
print(adupl)
# next line would crash
#print(selectionSort(adupl))
One fix is to only remove one copy of duplicates. This can for example be done using argmin which returns the index of the/one minimum, not its value.
def selectionSort2(arr):
arr = np.array(arr)
sorted = np.empty_like(arr)
for i in range(len(sorted)):
j = arr.argmin()
sorted[i] = arr[j]
arr = np.delete(arr, j)
return sorted
print(selectionSort2(adupl))
This works but is terribly inefficient because np.delete is more or less O(n). It is cheaper to swap the minimum element with a boundary element and then cut that off:
def selectionSort3(arr):
arr = np.array(arr)
sorted = np.empty_like(arr)
for i in range(len(sorted)):
j = arr[i:].argmin()
sorted[i] = arr[i + j]
arr[i], arr[i + j] = arr[i + j], arr[i]
return sorted
print(selectionSort3(adupl))
Looking at selectionSort3 we can observe that the separate output sorted is not actually needed, because arr has been sorted inplace already:
def selectionSort4(arr):
arr = np.array(arr)
for i in range(len(arr)):
j = arr[i:].argmin()
arr[i], arr[i + j] = arr[i + j], arr[i]
return arr
print(selectionSort4(adupl))
Sample output (adupl and output of selectionSort2-4):
[0 4 3 8 8 4 5 0 4 2]
[0 0 2 3 4 4 4 5 8 8]
[0 0 2 3 4 4 4 5 8 8]
[0 0 2 3 4 4 4 5 8 8]
Related
I did this code so I reverse sub array group of integers but actually it only reverse the first sub array only and I don't know why this is happening!!!
Here is the code:
def reverseInGroups(self, arr, N, K):
rev=list()
count=0
reach=K
limit=0
while limit<N-1:
rev[limit:reach]=reversed(arr[limit:reach])
limit=limit+K
reach=reach+K
if reach==N-1 or reach<N-1:
continue
elif reach>N-1:
reach=N-1
return rev
This is the the input,excpected output and my output:
For Input:
5 3
1 2 3 4 5
Your Output:
1 2 3 4 5
Expected Output:
3 2 1 5 4
I tried your code online and its fine, but you have one logic error in your function to get your desired output.
while limit<N-1:
rev[limit:reach]=reversed(arr[limit:reach])
limit=limit+K #3
reach=reach+K #6
if reach==N-1 or reach<N-1:
continue
elif reach>N-1:
reach=N #5
this is an image to see what I mean image description
You don't have to create new list rev, you can reverse items in list arr. For example:
def reverseInGroups(arr, N, K):
limit = 0
while limit < N:
arr[limit : limit + K] = reversed(arr[limit : limit + K])
limit += K
return arr
l = [1, 2, 3, 4, 5]
print(reverseInGroups(l, 5, 3))
Prints:
[3, 2, 1, 5, 4]
I suggest you use this simpler solution:
arr = [1, 2, 3, 4, 5]
n = 5
k = 3
new_arr = list()
for index in range(0, n - 1, k):
new_arr[index:index+k] = arr[index:index+k][::-1]
print(new_arr)
And the output is:
[3, 2, 1, 5, 4]
After putting this code in your function, it is as below:
def reverseInGroups(self, arr, n, k):
new_arr = list()
for index in range(0, n - 1, k):
new_arr[index:index+k] = arr[index:index+k][::-1]
return new_arr
we can do the loop in the increment of K and then reverse the array of that specific size
def reverseInGroups(self, arr, N, K):
# code here
for i in range(0, N -1 , K):
arr[i:i +K] = arr[i:i +K][::-1]
I have n rows and m columns I need a matrix which consists of consecutive m numbers like 1,2,3,4 this in each of the n rows that needs to be in ever increasing order.
example: 3 X 4 matrix\
**[\
[1, 2, 3, 4], \
[5, 6, 7, 8],\
[9, 10, 11, 12]\
]**
The intuition is very simple. What we need is our starting element in eaxh row should be the next element of the previous row's last element. That is the only tricky part in this problem.
For that we start our next row generation with arr[i-1][-1] to the arr[i-1][-1] + m. But for the first row generation we start from 1 since the matrix is empty.
Code
mat = []
n,m = map(int,input().split())
for row in range(n):
# if the row is starting row we start it with 1
# Else we assign k to the prev rows
if row == 0:
k = 1
else:
k = mat[row-1][-1] + 1
x = []
#the new row starts from previous rows last elemnt + 1
for j in range(k,k+m):
x.append(j)
mat.append(x)
print(mat)
First generate a continuous sequence of numbers and then adjust the format, with reference to either:(n and m represent the number of rows and columns respectively)
use the built-in functions, array to generate sequences, reshape to adjust the layout
import numpy as np
n, m = map(int, input().split())
res = np.arange(1, n*m+1).reshape(n, m)
print(res)
using list generative
items = list(range(1, m*n+1))
res = [items[i:i+m] for i in range(0, len(items), m)]
print(res)
here's a one liner to achieve that -
row, col = 3, 4
mat = [[col*i + j for j in range(1, col+1)] for i in range(row)]
print(mat)
I want to maximize the following function:
f(i, j, k) = min(A(i, j), B(j, k))
Where A and B are matrices and i, j and k are indices that range up to the respective dimensions of the matrices. I would like to find (i, j, k) such that f(i, j, k) is maximized. I am currently doing that as follows:
import numpy as np
import itertools
shape_a = (100 , 150)
shape_b = (shape_a[1], 200)
A = np.random.rand(shape_a[0], shape_a[1])
B = np.random.rand(shape_b[0], shape_b[1])
# All the different i,j,k
combinations = itertools.product(np.arange(shape_a[0]), np.arange(shape_a[1]), np.arange(shape_b[1]))
combinations = np.asarray(list(combinations))
A_vals = A[combinations[:, 0], combinations[:, 1]]
B_vals = B[combinations[:, 1], combinations[:, 2]]
f = np.min([A_vals, B_vals], axis=0)
best_indices = combinations[np.argmax(f)]
print(best_indices)
[ 49 14 136]
This is faster than iterating over all (i, j, k), but a lot of (and most of the) time is spent constructing the A_vals and B_vals matrices. This is unfortunate, because they contain many many duplicate values as the same i, j and k appear multiple times. Is there a way to do this where (1) the speed of numpy's matrix computation can be preserved and (2) I don't have to construct the memory-intensive A_vals and B_vals arrays.
In other languages you could maybe construct the matrices so that they container pointers to A and B, but I do not see how to achieve this in Python.
Perhaps you could re-evaluate how you look at the problem in context of what min and max actually do. Say you have the following concrete example:
>>> np.random.seed(1)
>>> print(A := np.random.randint(10, size=(4, 5)))
[[5 8 9 5 0]
[0 1 7 6 9]
[2 4 5 2 4]
[2 4 7 7 9]]
>>> print(B := np.random.randint(10, size=(5, 3)))
[[1 7 0]
[6 9 9]
[7 6 9]
[1 0 1]
[8 8 3]]
You are looking for a pair of numbers in A and B such that the column in A is the same as the row of B, and the you get the maximum smaller number.
For any set of numbers, the largest pairwise minimum happens when you take the two largest numbers. You are therefore looking for the max in each column of A, row of B, the minimum of those pairs, and then the maximum of that. Here is a relatively simple formulation of the solution:
candidate_i = A.argmax(axis=0)
candidate_k = B.argmax(axis=1)
j = np.minimum(A[candidate_i, np.arange(A.shape[1])], B[np.arange(B.shape[0]), candidate_k]).argmax()
i = candidate_i[j]
k = candidate_k[j]
And indeed, you see that
>>> i, j, k
(0, 2, 2)
>>> A[i, j]
9
>>> B[j, k]
9
If there are collisions, argmax will always pick the first option.
Your values i,j,k are determined by the index of the maximum value from the set {A,B}. You can simply use np.argmax().
if np.max(A) < np.max(B):
ind = np.unravel_index(np.argmax(A),A.shape)
else:
ind = np.unravel_index(np.argmax(B),B.shape)
It will return only two values, either i,j if max({A,B}) = max({A}) or j,k if max({A,B}) = max({B}). But if for example you get i,j then k can be any value that fit the shape of the array B, so select randomly one of this value.
If you also need to maximize the other value then:
if np.max(A) < np.max(B):
ind = np.unravel_index(np.argmax(A),A.shape)
ind = ind + (np.argmax(B[ind[1],:]),)
else:
ind = np.unravel_index(np.argmax(B),B.shape)
ind = (np.argmax(A[:,ind[0]]),) + ind
How can I search for the three maximum elements of a list and replace it at same index with its result when divided by 2.
Please what am I doing wrong:
input is: 2 5 8 19 1 15 7 20 11
output should be : 2 5 8 9.5 1 7.5 7 10 11
Index out of range is the result displayed
def numberInput(line):
lineInput = [int(i) for i in line.split()]
min1 = min(lineInput)
for j in range(len(lineInput)):
if lineInput[j]>min1 and lineInput[j] > lineInput[j+1]:
max1 = lineInput[j]/float(2)
else:
max1 = lineInput[j]/float(2)
lineInput[j] = max1
lineInput[j] = max1
return(lineInput)
number = '2 5 8 19 1 15 7 20 11'
print(numberInput(number))
If the order of list isn't important, you can simply sort the list in descending order and then replace the first 3 elements as
a = [2, 5, 8, 19, 1, 15, 7, 20, 11]
a.sort(reverse = True)
a[0] = a[0] / 2
a[1] = a[1] / 2
a[2] = a[2] / 2
Output
[10.0, 9.5, 7.5, 11, 8, 7, 5, 2, 1]
If the order is important,
import heapq
largest = heapq.nlargest(3, a)
for i in range(len(a)):
if a[i] in largest:
a[i] = a[i] / 2
Output
[2, 5, 8, 9.5, 1, 7.5, 7, 10.0, 11]
heapq.nlargest() is a function of heapq which can give you n largest numbers from a list. Since lists in Python do not have a replace function, the list had to be traversed once, and then replaced manually. Hope this resolves your issue.
Why wouldn't you just walk through the list once (it maybe a bit longer code, but definitely efficient)
def numberInput(line):
lineInput = [int(i) for i in line.split()]
n = len(lineInput)
if n <= 3:
return [i / 2 for i in lineInput]
max_pairs = [(lineInput[i], i) for i in range(3)] # keep track of 3 max's and their indices
max_pairs.sort(key = lambda x: -x) # sort in descending order
for i in range(3, n):
if lineInput[i] >= max_pairs[0][0]: # greater than the largest element
max_pairs = [(lineInput[i], i)] + max_pairs[:2]
elif lineInput[i] >= max_pairs[1][0]: # greater than second element
max_pairs = [max_pairs[0], (lineInput[i], i), max_pairs[1]]
elif lineInput[i] >= max_pairs[2][0]: # greater than third element
max_pairs = max_pairs[:2] + [(lineInput[i], i)]
for pair in max_pairs:
lineInput[pair[1]] = lineInput[pair[0]] / 2
return lineInput
Explanation: max_pairs is a set of three tuples, containing the maximum three elements and their indices
Note: I think the above is easiest to understand, but you can do it in a loop if you don't like all those ifs
This question already has answers here:
Sum slices of consecutive values in a NumPy array
(5 answers)
Closed 3 years ago.
I have a very long list of array numbers I would like to sum and place into a new array. For example the array:
[1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
would become:
[6,15,16,6,15,x]
if I was to sum every 3.
I cannot figure out how to go about it. I think possibly one problem is I do not know the length of my array - I do not mind losing the bottom bit of data if necessary.
I have tried the numpy.reshape function with no success:
x_ave = numpy.mean(x.reshape(-1,5), axis=1)
ret = umr_sum(arr, axis, dtype, out, keepdims)
I get an error:
TypeError: cannot perform reduce with flexible type
Cut the array to the correct length first then do a reshape.
import numpy as np
N = 3
a = np.array([1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8])
# first cut it so that lenght of a % N is zero
rest = a.shape[0]%N
a = a[:-rest]
assert a.shape[0]%N == 0
# do the reshape
a_RS = a.reshape(-1,N)
print(a_RS)
>> [[1 2 3]
[4 5 6]
[7 8 1]
[2 3 4]
[5 6 7]]
then you can simply add it up:
print(np.sum(a_RS,axis=1))
>> [ 6 15 16 9 18]
You can use a list comprehension do this:
ls = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
res = [sum(ls[i:i+3]) for i in range(0, len(ls), 3)]
[6, 15, 16, 9, 18, 8]
This will result in all the numbers being included in the resulting sum. If you don't want this to happen, then you can just check for it and replace the last sum with whatever value you want:
if (len(ls)%3) != 0:
res[-1] = 'x'
[6, 15, 16, 9, 18, 'x']
Or remove it entirely:
if (len(ls)%3) != 0:
res[:] = res[:-1]
[6, 15, 16, 9, 18]
Why don't you just simply use a list comprehension? E.g.
my_list = [1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8]
len_list = len(my_list) - len(my_list) % 3 # ignore end of list, s.t., only tuples of three are considered
[my_list[i] + my_list[i+1] + my_list[i+2] for i in range(0, len_list, 3)]