是否可以对带有reduce的列表进行排序?

时间:2019-05-08 17:18:42

标签: python python-3.x sorting

这是我做的一项练习。我当然可以使用 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

5 个答案:

答案 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]了-它就在那里打印xsx的中间值。如果不进行打印,我们可以将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]