为什么我不能在此函数中重新分配变量?

Why can't I reassign variables in this function?

这里是问题:

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.

这是我的代码:

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

当我测试它时,它是这样的:

>>> 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]

由于某些原因,我无法将函数中的变量x按升序重新赋值给odd_ints。有人知道我的代码中的问题吗?

你只需要将奇数的位置也保存起来,就可以进行替换:

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]))

输出:

[1, 3, 2, 8, 5, 4]

你可以这样做:

  1. 将赔率与索引分离成字典;
  2. 对赔率进行排序并将索引重置为奇数槽;
  3. 将这些赔率插入原始列表。

示例:

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]

修改了@eli-harold 的答案以使用更易读的语法:

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]))

或者,更简洁,

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

奖励:如果我们不应该就地排序(修改给定列表),以下方法将起作用:

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]