我得到这个作为练习。我当然可以使用 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
这是使用
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
的可选第三个参数将输出初始化为空列表。
我认为你误解了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
的第三个参数(即
[]
)是在我们初始化时指定的,排序应使用空列表。
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]
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
?会导致错误。
(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]
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]