Here is the question:
You will be given an array of numbers. You have to sort the odd numbers in ascending order while leaving the even numbers at their original positions.
Here is my code:
def sort_array(source_array):
odd_ints = []
for i in source_array:
if i % 2 == 1:
odd_ints.append(i)
odd_ints.sort()
else:
pass
counter = 0
for x in source_array:
if x % 2 == 1:
x = odd_ints[counter]
counter = 1
print(source_array)
else:
pass
return source_array
When I test it, it does this:
>>> sort_array([5, 3, 2, 8, 1, 4])
[5, 3, 2, 8, 1, 4]
[5, 3, 2, 8, 1, 4]
[5, 3, 2, 8, 1, 4]
[5, 3, 2, 8, 1, 4]
For some reason, I can't re-assign the variable x in the function to odd_ints in ascending order. Would anyone know the problem in my code?
CodePudding user response:
Modified answer by @eli-harold to use slightly more readable syntax:
def sort_array(source_array):
odd_ints = []
positions = []
for i, elem in enumerate(source_array):
if elem % 2:
odd_ints.append(elem) # keep the values
positions.append(i) # keep the position
odd_ints.sort() # sort for replacement
for pos, elem in zip(positions, odd_ints):
source_array[pos] = elem # place the sorted values
return source_array
print(sort_array([5, 3, 2, 8, 1, 4]))
Or, being more concise,
def sort_array(source_array):
positions, odd_ints = zip(*[(i, elem)
for i, elem in enumerate(source_array)
if elem % 2])
pos = iter(positions)
for elem in sorted(odd_ints):
source_array[next(pos)] = elem
return source_array
Bonus: if we should not sort inplace (modify given list), the following will work:
def sort_array(arr):
odd_sorted_it = iter(sorted(el for el in arr if el % 2))
return [el if not el % 2 else next(odd_sorted_it) for el in arr]
CodePudding user response:
You just need to save the positions of the odd integers as well to replace them:
def sort_array(source_array):
odd_ints = []
positions = []
counter = 0 #need counter to get positions
for i in source_array:
if i % 2 == 1:
odd_ints.append(i) #keep the values
positions.append(counter) #keep the position
counter = 1
odd_ints.sort() #sort for replacement
counter2 = 0 #need second counter to place sorted list
for pos in positions:
source_array[pos] = odd_ints[counter2] #place the sorted values
counter2 = 1
return source_array
print(sort_array([5, 3, 2, 8, 1, 4]))
Output:
[1, 3, 2, 8, 5, 4]
CodePudding user response:
You can do this:
- Separate the odds with indexes into a dict;
- Sort the odds and reset the indexes into odd slots;
- Insert those odds into the original list.
Example:
def sort_the_odds(li):
odds={idx:n for idx,n in enumerate(li) if n%2}
for idx,val in zip([t[0] for t in sorted(odds.items())],
[t[1] for t in sorted(odds.items(), key=lambda t: t[1])]):
li[idx]=val
return li
>>> sort_the_odds([10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
[10, 1, 8, 3, 6, 5, 4, 7, 2, 9]
>>> sort_the_odds([5, 3, 2, 8, 1, 4])
[1, 3, 2, 8, 5, 4]
