这是我做的一项练习。我当然可以使用 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
答案 0 :(得分: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]
的值的列表以及大于{的所有值的列表{1}}。使用b
的第三个可选参数将输出初始化为空列表。
答案 1 :(得分:3)
我认为您误会了reduce在这里的工作原理。 Reduce在某些其他语言(例如Haskell)中与 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
仍然困扰着您,How does reduce work?包含一些不错的解释。)
我们的特定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
的第三个参数(即[]
)。 < / p>
答案 2 :(得分: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]
答案 3 :(得分: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
会追加新元素,然后交换list中的最后两个元素(如果它们不是按升序排列)。
这意味着my_sort
个数字的每次运行都会向右“移动”,直到发生下一个数字更大的地方。
开始需要if not acc
-注意reduce
的第三个参数是[]
,这意味着在每个func
的{{1}}的第一次执行期间,func的第一个参数是{ {1}},所以问reduce
?会导致错误。
答案 4 :(得分: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]