【问题标题】:Using the map function to iterate over values in a list of dictionaries in Python在 Python 中使用 map 函数迭代字典列表中的值
【发布时间】:2018-01-03 15:20:27
【问题描述】:

我一直在尝试处理存储在字典列表中的数据,并将其存储在另一个元组列表中。例如说我有以下数据:

triangles= [{"name": "triangle1", "base":3, "height":4}, 
            {"name": "triangle2", "base":5, "height":12}, 
            {"name": "triangle3", "base":8, "height":15}
           ]

我想通过以下我无法更改的函数运行所有数据:

def hypotenuse(base, height):
    hyp_sq=base**2+height**2

    return hyp_sq**(1.0/2.0)

理想情况下,在计算完所有数据后,我想根据三角形的斜边长度对三角形进行排序,并且我想返回以下格式的元组列表:

hypotenuse_results=[("triangle1", 5), ("triangle2", 13), ("triangle3", 17)]

我知道我必须将 map() 函数与 sorted() 结合使用,但我不知道如何仅传递与“base”和“height”键对应的值。

如果有人能指出我正确的方向,将不胜感激。

谢谢

【问题讨论】:

  • 使用map()吗?或者你只是认为你需要?
  • 我认为我需要这样做。 Map 可以让你在一个列表上运行一个函数,对吧?

标签: python list sorting dictionary list-comprehension


【解决方案1】:

大约在 1993 年,Python 得到了 lambda、reduce()、filter() 和 map(),感谢 Lisp 黑客,他错过了它们并提交了工作补丁。在 2000 年引入列表推导之后,这些 Lisp 风格的构造在 Python 中被认为有点陌生。所以不,您不需要 map,您可以使用列表推导或生成器表达式。

你可以让你的 hypotenuse 函数接受额外的参数并忽略它们:

def hypotenuse(base, height, **kwargs):
    hyp_sq=base**2+height**2
    return hyp_sq**(1.0/2.0)

然后你可以使用列表推导:

hypotenuse_results = [(t['name'], hypotenuse(**t)) for t in triangles]
hypotenuse_results.sort(key=lambda pair: pair[1])

即使对于较大的len(triangles),这也应该表现得足够好。生成器表达式版本为:

unsorted_results = ((t['name'], hypotenuse(**t)) for t in triangles)
hypotenuse_results = sorted(unsorted_results, key=lambda pair: pair[1])

分析两个解决方案并在此处发布将是一个很好的练习。

谢谢。有没有办法在不修改斜边函数的情况下做到这一点? – 取消

当然!只需使用两个参数调用它:

hypotenuse_results = [(t['name'], hypotenuse(t['base'], t['height'])) for t in triangles]
hypotenuse_results.sort(key=lambda pair: pair[1])

请注意,公认的解决方案是分配一个实际列表并将其丢弃,因此如果您担心内存占用,您可能希望使用生成器表达式而不是列表推导式(如果 len(triangles) 很大但总是好习惯):

hypotenuse_results = sorted(
    ((t['name'], hypotenuse(t['base'], t['height'])) for t in triangles), 
    key=lambda x: x[1]
)

【讨论】:

  • 谢谢。有没有办法在不修改斜边函数的情况下做到这一点?
  • 当然!称呼它为hypotenuse(t['base'], t['height'])
  • @canecse 只需将 hypotenuse(**t) 更改为 hypotenuse(t["base"],t["height"]) 但如果您无法编辑该函数,那么您应该在问题中输入这种信息
  • sorted([(t['name'], hypotenuse(t['base'], t['height'])) for t in triangles], key=lambda t: t[1])
【解决方案2】:

你需要修改你的斜边函数,对于一些这样的:

def hypotenuse(triangle):
    hyp_sq=triangle["base"]**2 + triangle["height"]**2
    return (triangle["name"], hyp_sq**(1.0/2.0))

map 会返回一个元组的生成器,当每个元组都是 (name, hyp) 时,只需使用元组的第二个元素进行排序:

sorted(map(hypotenuse, triangles), key=lambda x: x[1])

更新:

因为你不能改变斜边函数,你可以只使用列表推导:

sorted([(t['name'], hypotenuse(t['base'], t['height'])) for t in triangles], key=lambda x: x[1])

【讨论】:

  • 这样就解决了问题。但是,如果我无法修改函数 hypotenuse,因为给我的实际问题中的函数是通过库导入的。
  • @canecse 如果你不能改变函数,你不能在这种情况下使用 map,因为原始的 hypotenuse 函数只返回一个没有三角形名称的值,所以,map generator 返回一个 hypo值,但是,您需要一个元组列表。
  • 你可以创建另一个函数,可以是一个 lambda,调用 hypotenuse 并创建一个你想要的元组,像这样:sorted(map(lambda t: (t['name'], hypotenuse(t['base'], t['height'])), triangles), key=lambda x: x[1])
【解决方案3】:

由于您的 hypotenuse 函数在这里工作正常,您可以构造一个推导来创建您的元组列表:

from operator import itemgetter

result = sorted(((x['name'], hypotenuse(x['base'], x['height'])) for x in triangles), key = itemgetter(1))

print(result)

这给出了:

[('triangle1', 5), ('triangle2', 13), ('triangle3', 17)]

或者如果你真的想使用map(),你可以试试这个:

result = sorted(map(lambda x: (x['name'], hypotenuse(x['base'], x['height'])), triangles), key = itemgetter(1))

注意:您可以使用lambda x: x[1] 代替operator.itemgetter(1)。这只是一个偏好问题。如果您有兴趣,可以阅读this 了解两者之间的表现,以及各自的优缺点。

更新:

@Paulo Scardine 在 cmets 中指出,如果将来 triangle 变得更大,在 sorted() 中使用生成器表达式会更有效。这是因为列表推导会在现场创建一个列表,但sorted() 在此过程中无论如何都会删除此列表,因此在不需要时传入列表是一种浪费。对于第二个示例,这不是问题,因为map() 已经返回了一个生成器。我更新了上面的代码以考虑这些建议。

【讨论】:

  • @NickA 看here,它的性能稍微好一点。这里应该没什么区别,我只是习惯了。
  • 另外,itemgetter(1)lambda x: x[1] 更容易理解,和它的表亲 attrgetter(name) 一样
  • @mata 我完全同意。我认为它也更灵活。我发现一个很大不同的例子是一次获取多个元素:itemgetter(2,4,6)lambda x: (x[2], x[4], x[6])。到目前为止,我更喜欢第一种方式。
  • @NickA 我不明白你的问题,hypotenuse 返回一个float,但 OP 想要一个 int 在输出中。当然,他们将类型转换为匹配输出并没有错。
  • 好答案。对于较小的len(triangles),这无关紧要,但对于较大的输入,生成器表达式更好(因为列表推导式分配的是sorted 正在丢弃的实际列表)。
猜你喜欢
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 2012-09-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 1970-01-01
相关资源
最近更新 更多