简体   繁体   English

为什么我在 Python 中通过 reduce 对列表进行排序的代码会抛出错误?

[英]Why is my code for sorting a list via reduce in Python throwing an error?

I thought of a one-liner to sort a list in Python, but it hasn't been working.我想到了用 Python 对列表进行排序的单行程序,但没有奏效。 I thought that I could use reduce to go through the list and swap elements as needed, like in bubble sort.我认为我可以使用reduce来遍历列表并根据需要交换元素,就像冒泡排序一样。 But the interpreter is being frustrating today:但是今天的解释器令人沮丧:

from functools import  reduce

def reduce_sort(*lst):
    sorter = lambda x, y: y, x if x > y else x, y
    return reduce(sorter, lst)

reduce_sort(5, 4, 6, 7, 1)

This is giving me NameError: name 'x' is not defined这给了我NameError: name 'x' is not defined

Does anyone have any idea why this is happening?有谁知道为什么会这样?

sorter is a tuple: sorter是一个元组:

import ast

print(ast.dump(
  ast.parse("lambda x, y: y, x if x > y else x, y")
))

Try it online! 在线试试吧!

It actually parses to this:它实际上解析为:

Module(body=[Expr(value=
  Tuple(elts=[
    Lambda(
      args=arguments(posonlyargs=[], args=[arg(arg='x', annotation=None, type_comment=None), arg(arg='y', annotation=None, type_comment=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]),
      body=Name(id='y', ctx=Load())
    ),
    IfExp(
      test=Compare(left=Name(id='x', ctx=Load()), ops=[Gt()], comparators=[Name(id='y', ctx=Load())]),
      body=Name(id='x', ctx=Load()),
      orelse=Name(id='x', ctx=Load())
    ),
    Name(id='y', ctx=Load())
  ],
ctx=Load()))],type_ignores=[])

So it's equivalent to所以它相当于

sorter = (lambda x, y: y), (x if x > y else x), y

...where the second expression, x if x > y else x , will raise an exception because it doesn't know what x is. ...其中第二个表达式x if x > y else x将引发异常,因为它不知道x是什么。

You should explicitly specify that the if expression evaluates to tuples:您应该明确指定if表达式计算为元组:

sorter = lambda x, y: (y, x) if x > y else (x, y)

Now sorter is a function, but the code as a whole won't work because on the second iteration of reduce x will become a tuple (one of those returned by the if expression) that'll be compared to y , which is an integer.现在sorter是一个函数,但整个代码将不起作用,因为在reduce x的第二次迭代中将成为一个元组( if表达式返回的元组之一),将与y进行比较,后者是一个整数. Such operation is not possible, so you'll get another error, now at runtime.这样的操作是不可能的,所以你会得到另一个错误,现在在运行时。

Sorting with functools.reduce is a good idea.使用functools.reduce排序是个好主意。

Why your code currently doesn't work为什么您的代码目前不起作用

However, once you start combining two or more elements from the initial list into a sorted sublist, your function sorter = lambda x, y: y, x if x > y else x, y is no longer adequate: it only knows how to combine two elements into a length-2 list;但是,一旦您开始将初始列表中的两个或多个元素组合到一个排序的子列表中,您的函数sorter = lambda x, y: y, x if x > y else x, y不再足够:它只知道如何组合将两个元素放入一个长度为 2 的列表中; it doesn't know how to combine two sorted lists into a sorted list.它不知道如何将两个排序列表组合成一个排序列表。

Example:例子:

initial list =   [17, 45, 100, 96, 29, 15, 0, 32, 4, 100, 61, 11, 85, 96, 2, 75, 88, 51, 16, 27, 68, 74, 99, 27, 83, 38, 96, 40, 73, 99, 33, 36, 86, 54, 50, 36, 44, 56, 0, 62, 62, 87, 64, 14, 63, 78, 98, 64, 60, 57, 56, 80, 80, 32, 40, 51, 64, 29, 21, 43, 63, 44, 35, 25, 37, 10, 13, 9, 34, 10, 39, 70, 14, 33, 49, 16, 80, 50, 14, 82, 51, 82, 67, 10, 20, 6, 59, 5, 31, 62, 83, 92, 13, 59, 71, 65, 1, 25, 78, 45]
began reducing = [[17, 45], [96, 100], [15, 29], [0, 32], 4, 100, 61, 11, 85, 96, 2, 75, 88, 51, 16, 27, 68, 74, 99, 27, 83, 38, 96, 40, 73, 99, 33, 36, 86, 54, 50, 36, 44, 56, 0, 62, 62, 87, 64, 14, 63, 78, 98, 64, 60, 57, 56, 80, 80, 32, 40, 51, 64, 29, 21, 43, 63, 44, 35, 25, 37, 10, 13, 9, 34, 10, 39, 70, 14, 33, 49, 16, 80, 50, 14, 82, 51, 82, 67, 10, 20, 6, 59, 5, 31, 62, 83, 92, 13, 59, 71, 65, 1, 25, 78, 45]
sorter([15, 29], [0, 32]) = ???

How to fix this sorter function?如何修复此sorter功能? What we want is to be able to merge two sorted lists into a sorted list.我们想要的是能够将两个排序列表合并为一个排序列表。 Does this ring a bell?这是否敲响了警钟? Yes!是的! It's the merge function from mergesort .这是来自mergesortmerge功能。

We could implement it ourselves... Or we can look in the python standard modules if it isn't already implemented somewhere.我们可以自己实现它......或者如果它没有在某处实现,我们可以查看 python 标准模块。 It is.这是。 It's called heapq.merge .它被称为heapq.merge

Replacing sorter with heapq.mergeheapq.merge替换sorter

Let's replace your sorter with heapq.merge :让我们用heapq.merge替换你的sorter

import random
import functools
import heapq
ll = [random.randint(0,100) for i in range(100)]
list(functools.reduce(heapq.merge, ll))
# TypeError: 'int' object is not iterable

Oops!哎呀! heapq.merge expects two iterables. heapq.merge需要两个可迭代对象。 Initially our list doesn't contains lists, it contains single elements.最初我们的列表不包含列表,它包含单个元素。 We need to replace these single elements with singleton lists or singleton tuples:我们需要用单例列表或单例元组替换这些单个元素:

import random
import functools
import heapq
ll = [(random.randint(0,100),) for i in range(100)]
list(functools.reduce(heapq.merge, ll))
# [3, 3, 4, 5, 5, 5, 7, 8, 8, 10, 11, 13, 15, 15, 15, 15, 16, 16, 17, 18, 19, 20, 20, 20, 24, 25, 25, 27, 27, 28, 30, 30, 30, 30, 31, 32, 33, 33, 38, 38, 39, 39, 41, 42, 43, 43, 43, 46, 46, 47, 49, 50, 51, 52, 53, 55, 62, 63, 63, 64, 64, 64, 65, 66, 67, 68, 69, 71, 72, 72, 72, 72, 73, 73, 73, 74, 78, 79, 82, 82, 83, 83, 86, 86, 86, 86, 89, 91, 92, 93, 95, 96, 96, 96, 97, 98, 99, 99, 100, 100]

It works!有用! Note the ( ,) construct inside of ll that makes singleton tuples.请注意ll内部的( ,)构造,它生成单例元组。 If you don't like tuples and would prefer lists, you can use [ ] instead of ( ,) .如果您不喜欢元组并且更喜欢列表,则可以使用[ ]代替( ,)

Of course, you want to be able to sort a list that contains numbers, not singleton tuples.当然,您希望能够对包含数字而不是单例元组的列表进行排序。 So let's add lambda x: (x,) or lambda x: [x] to our mix:因此,让我们将lambda x: (x,)lambda x: [x]到我们的组合中:

The final solution最终的解决方案

import functools
import heapq
def reduce_sort(ll):
  list(functools.reduce(heapq.merge, map(lambda x: (x,), ll)))

import random
ll = [random.randint(0,100) for i in range(100)]
reduce_sort(ll)
# [3, 3, 4, 5, 5, 5, 7, 8, 8, 10, 11, 13, 15, 15, 15, 15, 16, 16, 17, 18, 19, 20, 20, 20, 24, 25, 25, 27, 27, 28, 30, 30, 30, 30, 31, 32, 33, 33, 38, 38, 39, 39, 41, 42, 43, 43, 43, 46, 46, 47, 49, 50, 51, 52, 53, 55, 62, 63, 63, 64, 64, 64, 65, 66, 67, 68, 69, 71, 72, 72, 72, 72, 73, 73, 73, 74, 78, 79, 82, 82, 83, 83, 86, 86, 86, 86, 89, 91, 92, 93, 95, 96, 96, 96, 97, 98, 99, 99, 100, 100]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM