可以用reduce对列表进行排序吗?

问题描述 投票:0回答:6

我得到这个作为练习。我当然可以使用 sorted() 或 Python 标准库中的其他方式对列表进行排序,但在这种情况下我不能。我认为我只应该使用reduce()

from functools import reduce
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(lambda a,b : (b,a) if a > b else (a,b), arr)

我得到的错误:

TypeError: '>' not supported between instances of 'tuple' and 'int'

这是预期的,因为我的reduce函数将一个元组插入到int数组中,而不是2个单独的整数。然后将元组与整数进行比较...

有没有办法将 2 个数字插入到列表中,并且只对列表中的每隔两个数字运行该函数?或者使用reduce()交换数字的方法?

文档对reduce函数的描述很少,所以我现在没有想法。 https://docs.python.org/3/library/functools.html?highlight=reduce#functools.reduce

python python-3.x sorting
6个回答
6
投票

这是使用

reduce
对列表进行排序的一种方法:

arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(
    lambda a, b: [x for x in a if x <= b] + [b] + [x for x in a if x > b],
    arr,
    []
)
print(sorted_arr)
#[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]

在每个归约步骤中,构建一个新的输出列表,该列表连接所有小于或等于

b
[b]
的值的列表以及所有大于
b
的值的列表。使用
reduce
的可选第三个参数将输出初始化为空列表。


4
投票

我认为你误解了reduce在这里的工作原理。在某些其他语言(例如 Haskell)中,Reduce 与 right-fold 同义。第一个参数需要一个带有两个参数的函数:一个 accumulator 和一个要累加的元素。

让我们来破解它:

arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
reduce(lambda xs, x: [print(xs, x), xs+[x]][1], arr, [])

这里,

xs
是累加器,
x
是要累加的元素。不要太担心
[print(xs, x), xs+[x]][1]
– 它只是打印
xs
x
的中间值。如果没有打印,我们可以将 lambda 简化为
lambda xs, x: xs + [x]
,它只是附加到列表中。

以上输出:

[] 17
[17] 2
[17, 2] 3
[17, 2, 3] 6
[17, 2, 3, 6] 1
[17, 2, 3, 6, 1] 3
[17, 2, 3, 6, 1, 3] 1
[17, 2, 3, 6, 1, 3, 1] 9
[17, 2, 3, 6, 1, 3, 1, 9] 5
[17, 2, 3, 6, 1, 3, 1, 9, 5] 3

正如我们所看到的,

reduce
传递一个累积列表作为第一个参数,一个新元素作为第二个参数。(如果
reduce
仍然让你感到困惑,reduce如何工作?包含一些很好的解释。 )

我们特定的 lambda 在每次“迭代”时将一个新元素插入到累加器中。这暗示了插入排序:

def insert(xs, n): """ Finds first element in `xs` greater than `n` and returns an inserted element. `xs` is assumed to be a sorted list. """ for i, x in enumerate(xs): if x > n: return xs[:i] + [n] + xs[i:] return xs + [n] sorted_arr = reduce(insert, arr, []) print(sorted_arr)

这将打印正确排序的数组:

[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]

请注意,reduce

的第三个参数(即
[]
)是在我们
初始化时指定的,排序应使用空列表。


1
投票
忍者!但是,是的,这是一种插入排序。

def insert(acc, e): for i, x in enumerate(acc): if x > e: acc.insert(i, e) return acc acc.append(e) return acc reduce(insert, [1, 2, 6, 4, 7, 3, 0, -1], [])

输出

[-1, 0, 1, 2, 3, 4, 6, 7]
    

1
投票
经过一番思考,我得出的结论是,如果允许多次使用

reduce

,也可以进行基于交换的排序。即:

from functools import reduce arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3] def func(acc,x): if not acc: return [x] if acc[-1]<x: return acc+[x] else: return acc[:-1]+[x]+acc[-1:] def my_sort(x): moresorted = reduce(func,x,[]) print(moresorted) if x==moresorted: return moresorted else: return my_sort(moresorted) print('arr:',arr) arr_sorted = my_sort(arr) print('arr sorted:',arr_sorted)

输出:

arr: [17, 2, 3, 6, 1, 3, 1, 9, 5, 3] [2, 3, 6, 1, 3, 1, 9, 5, 3, 17] [2, 3, 1, 3, 1, 6, 5, 3, 9, 17] [2, 1, 3, 1, 3, 5, 3, 6, 9, 17] [1, 2, 1, 3, 3, 3, 5, 6, 9, 17] [1, 1, 2, 3, 3, 3, 5, 6, 9, 17] [1, 1, 2, 3, 3, 3, 5, 6, 9, 17] arr sorted: [1, 1, 2, 3, 3, 3, 5, 6, 9, 17]

出于教育目的,我将

print(moresorted)

 放在 
func
 内,如果您愿意,可以将其删除。 

现在解释:

my_sort

是递归函数,每次运行它列表都会变得越来越排序。在 
func
 中用作函数的 
reduce
 会追加新元素,然后交换列表的最后 2 个元素(如果它们不是按升序排列)。
这意味着每次运行 
my_sort
 数字都会向右“移动”,直到出现下一个更大的数字。
启动时需要 
if not acc
 - 请注意,
reduce
 的第三个参数是 
[]
,这意味着在每个 
func
 中第一次执行 
reduce
 时,func 的第一个参数是 
[]
,所以问 
acc[-1]<x
?会导致错误。


0
投票
让我们了解一下

(1)Reduce的用法基本上是将表达式减少为单个最终值 (2)reduce()存储中间结果,只返回最终求和值
(3)我们将使用reduce获取最小元素,将其追加到sorted_list并从原始列表中删除
(4)现在reduce将对其余元素起作用并再次重复步骤3
(5)while list_nums: 将运行直到列表变空

list_of_nums = [1,19,5,17,9] sorted_list=[] while list_of_nums: maxvalue=reduce(lambda x,y: x if x<y else y,list_of_nums) sorted_list.append(maxvalue) list_of_nums.remove(maxvalue) print(sorted_list)

[1,5,9,17,19]


0
投票
而不是只知道如何将两个整数合并到一个排序元组中的

lambda a,b : (b,a) if a > b else (a,b)

,您需要一个知道如何将两个排序元组合并到一个排序元组中的函数。

这正是归并排序中的函数

merge

此函数已存在于 python 标准库的模块

heapq

 中: 
https://docs.python.org/3/library/heapq.html#heapq.merge

from functools import reduce from heapq import merge arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3] sorted_arr = list(reduce(merge, [(x,) for x in arr])) print(sorted_arr) # [1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
    
© www.soinside.com 2019 - 2024. All rights reserved.