[英]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")
))
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
排序是个好主意。
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
.这是来自
mergesort
的merge
功能。
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
。
sorter
with heapq.merge
heapq.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]
到我们的组合中:
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.