【问题标题】:Is it possible to sort a list with reduce?是否可以使用reduce对列表进行排序?
【发布时间】:2019-09-26 11:55:36
【问题描述】:

这是作为练习的。我当然可以使用 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 个单独的整数。然后将元组与 int 进行比较...

有没有办法将 2 个数字插入到列表中,并且只对列表中的每个第二个数字运行该函数?还是一种使用 reduce() 交换数字的方法?

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

【问题讨论】:

  • 有可能——一种方法是反复减少以找到最小值。
  • 其他人已经展示了许多如何使用reduce 执行插入排序的方法。我想指出,如果你必须使用reduce,这个选择是很自然的,因为插入排序属于所谓的在线排序算法的范畴,这意味着它可以工作一个接一个地出现新值(它不需要知道所有值才能开始工作)。

标签: python python-3.x sorting


【解决方案1】:

让我们理解这一点
(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]

【讨论】:

  • 没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请edit您的问题并解释它如何比OP提供的更好。
  • 仅代码(和仅链接)响应最好保留为评论,而不是答案。虽然此代码可能会解决 OP 的问题,但最好包括说明您的代码如何解决 OP 的问题。通过这种方式,未来的访问者可以从您的帖子中学习,并将其应用到他们自己的代码中。 SO 不是编码服务,而是知识资源。高质量、自包含、完整的答案更有可能获得支持,并且是 SO 平台具有的一些优势,使其与论坛区分开来。您可以edit 添加解释,并使用源文档补充您的推理。
【解决方案2】:

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

让我们破解它:

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 的第三个参数(即[])是指定的,因为我们初始化排序应该使用一个空列表。

【讨论】:

  • 您能解释一下[1] 索引的用法吗?我以前从未使用过 reduce。
  • @pstatix [print(xs, x), xs+[x]][1] – 这部分?在这里,我只是创建一个列表并对其进行索引。它是temp = [print(xs, x), xs + [x]]; print(temp[1]) 的同义词。它不与reduce混合。 :)
【解决方案3】:

经过一番思考,我得出结论,如果允许您多次使用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 是递归函数,随着它的每次运行,列表变得越来越有序。在reduce 中用作函数的func 确实追加了新元素,然后如果它们不是升序,则交换列表的最后两个元素。 这意味着在my_sort 的每次运行中,数字都会向右“移动”,直到下一个数字更大。 启动需要if not acc - 请注意reduce 的第三个参数是[],这意味着在第一次执行func 中每个reduce func 的第一个参数是[],所以问acc[-1]&lt;x?会导致错误。

【讨论】:

    【解决方案4】:

    忍者!但是,是的,它是一种插入排序。

    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]
    

    【讨论】:

      【解决方案5】:

      这是使用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]
      

      在每个 reduce 步骤中,构建一个新的输出列表,该列表连接所有小于或等于 b[b] 的值的列表以及所有大于 b 的值的列表。使用reduce 的可选第三个参数将输出初始化为一个空列表。

      【讨论】:

      • 简洁的快速排序 lambda。
      • 这不是快速排序。
      • 这是插入排序。
      • 对了。我认为[x for x in a if x &lt; b] + [b] + [x for x in a if x &gt; b] 看起来类似于a Haskell implementation of quicksort。但我现在看到,原理在于在每次折叠时插入一个元素
      猜你喜欢
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 2018-04-20
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-21
      相关资源
      最近更新 更多