python-3.x max()函数使用键参数产生意外结果

lqfhib0f  于 2022-12-14  发布在  Python
关注(0)|答案(5)|浏览(135)

names.txt:

Ben
Lukasz
Filippe
Sam
Artur

代码:

full_names = (name.strip() for name in open('names.txt'))
length = ((name, len(name)) for name in full_names)
longest = max(length, key=lambda x: x[1] <= 5)
print(longest)

结果总是Ben,但是,我想得到符合条件(x〈=5)的最长名称。Artur
如何修改max()以实现此输出?
如果删除条件并将其设置为:max(length, key=lambda x: x[1]),它工作得很好。

sg2wtvxw

sg2wtvxw1#

If you want to filter the possible values, don't do that with the key, just filter with a generator expression and then pass that to max :

max((x for x in length if x[1] <= 5), key=lambda x: x[1])
# Or without a lambda:
from operator import itemgetter
max((x for x in length if x[1] <= 5), key=itemgetter(1))

You could define the key to achieve this in a roundabout way, e.g. with:

max(length, key=lambda x: x[1] if x[1] <= 5 else -1)

so all lengths greater than the limit are treated as lengths of -1 ; this will misbehave when all the inputs fail the filter though (claiming a max exists when nothing passed the filter), so it's up to you if that's acceptable.
In practice, it's kinda silly to decorate with the length when it can just be cheaply computed live, so:

full_names = (name.strip() for name in open('names.txt'))
longest = max((x for x in full_names if len(x) <= 5), key=len)

is probably what I'd do.

yduiuuwa

yduiuuwa2#

您需要 filterfull_names以仅保留长度为<= 5的项,然后 * 查找最大值。请记住,您可以使用max函数的key参数将每个项Map到不同的值。例如:

filtered_names = [name for name in full_names if len(name) <= 5]
longest = max(filtered_names, key=len)

这里,len函数被调用用于filtered_names中的每个元素,并且该函数的结果被用于计算max。
您可以将这两行合并为一行,并通过使用生成器而不是创建filtered_names列表来保存一个循环

longest = max(name for name in full_names if len(name) <= 5,
              key=len)

如果你 * 真的 * 想使用你定义的length列表,你仍然需要过滤掉不满足条件的元素,然后 * 用length(在length的每个元素的1索引处)找到max

filtered_length = [item for item in length if item[1] <= 5]
longest = max(filtered_length, key=lambda item: item[1])[0]

max返回lengthitem,它在item[1]处具有最大值。由于item是一个同时包含名称和长度的元组,因此我们使用[0]元素来获取最长的名称。在一行中:

longest = max(item for item in length if item[1] <= 5, key=lambda item: item[1])[0]
bnlyeluc

bnlyeluc3#

第一个问题是你实际上并没有比较名字的长度;您要比较名称长度是否小于或等于5。基本上,您要根据第二列从该表中取出最大值:

Ben     True
Lukasz  False
Filippe False
Sam     True
Artur   True

为了解决这个问题,你需要lambda表达式来返回实际的长度:

full_names = (name.strip() for name in open('names.txt'))
length = ((name, len(name)) for name in full_names)
longest = max(length, key=lambda x: x[1])
print(longest)

这将生成下表,并根据第二列(即Filippe)选择一个表:

Ben     3
Lukasz  6
Filippe 7
Sam     3
Artur   5

如果只想考虑包含五个或更少字母的名称,可以进行以下过滤:

longest = max(filter(lambda x: x[1] <= 5, length), key=lambda x: x[1])

或者对于长度大于5的名称,让lambda返回零:

longest = max(length, key=lambda x: x[1] if x[1] <= 5 else 0)

最后一种方法将产生以下结果,并再次根据第二列进行拾取:

Ben     3
Lukasz  0
Filippe 0
Sam     3
Artur   5
ykejflvf

ykejflvf4#

∮问题是
您面临的问题是,您对max()key=参数的作用有误解。它通过调用给定的函数为每个处理的项目分配一个键值,然后通过比较这些键值返回最大元素。在您的情况下,它分配:

  • 本-〉周二
  • 卢卡斯-〉假
  • 菲利普-〉错误
  • Sam -〉正确
  • 阿图尔-〉正确

由于bool值只是int s的一种特殊情况,因此键的等效表示形式为

  • 本-〉1
  • 卢卡斯-〉0
  • 菲利普-〉0
  • 山姆-〉1
  • 阿图尔-〉1

那么max()将返回具有最大键的元素"Ben",因为以下项都没有分配更大的键(另请参见:稳定分选)。

解决方案

你想得到最长的项目,有五个或更少的字符。我们可以通过以下方式实现:

longest = max(full_names, key=lambda name: (length := len(name)) * (length <= 5))

在这里我们使用了上面的事实,即bool s就是int s,所以每个长度都乘以True,即1,如果它满足条件并因此不变,如果条件(〈=5)不满足,长度将乘以False,即0,因此为零。

nnsrf1az

nnsrf1az5#

首先,你应该过滤序列,然后找到过滤后的序列中的最大值。

full_names = (name.strip() for name in open('names.txt'))
longest = max(filter(lambda x:len(x) <= 5, full_names), key=len)
print(longest)

相关问题