【问题标题】:lambda in python can iterate dict?python中的lambda可以迭代dict吗?
【发布时间】:2015-10-12 09:09:30
【问题描述】:

我最近有一个面试。面试官问我在python中迭代dict的方法。我说的所有方式都使用 for 语句。但他告诉我 lambda 怎么样?

我感到很困惑,我认为 lambda 是一个匿名函数,但它是如何迭代一个 dict 的呢?像这样的一些代码:

new_dict = sorted(old_dict.items(), lambda x: x[1]) # sorted by value in dict

但在这段代码中,lambda 被用作提供比较键的函数。这个问题你怎么看?

【问题讨论】:

  • 没有更多背景信息,我们无法告诉你面试官是否知道他问了什么。
  • 另外,请注意,使用mapsorted 以及其他迭代函数(enumerate 等)也将使用for,在引擎盖的某个地方。
  • @jonrsharpe 通常这些函数是用 C 编写的,严格来说不要使用 Python for
  • 面试官很奇怪的问题
  • @Andrey 这是真的(对于 CPython),但不清楚这是否是相关的区别。

标签: python dictionary lambda


【解决方案1】:

您不会使用 lambda 进行迭代。在 Python 中迭代一个可迭代对象有以下几种方式:

  1. for 声明(你的答案)
  2. 理解,包括列表[x for x in y]、字典{key: value for key, value in x}和集合{x for x in y}
  3. 生成器表达式:(x for x in y)
  4. 传递给将对其进行迭代的函数(mapallitertools 模块)
  5. 手动调用next函数,直到StopIteration发生。

注意:除非您稍后迭代该生成器,否则 3 不会对其进行迭代。如果是 4,则取决于功能。

对于迭代特定的集合,如 dict 或 list,可以使用更多技术,如 while col: remove element 或索引切片技巧。

现在lambda 出现了。您可以在其中一些函数中使用 lambda,例如:map(lambda x: x*2, [1, 2, 3])。但是这里的lambda与迭代过程本身无关,可以传递一个正则函数map(func, [1, 2, 3])

【讨论】:

  • 如果要将推导式与生成器表达式分开,则应包括字典推导式和集合推导式。请注意,生成器表达式/理解确实包含 for 作为其语法的一部分。
  • @jonrsharpe 他们包括 for 但 OP 明确表示“for statement”,所以他不只是说“for keyword”。我将包括 dict/set 理解,但它不是关于将理解与生成器表达式分开。这两者本质上是不同的,而 dict/set 与 list 本质上是相同的。
  • 方法不止4种。例如,您可以使用while d: d.popitem()
  • 如果你写了一个 Y 组合器,你也许可以使用 lambdas 进行迭代。蟒蛇?上帝没有。
  • @NamitaMaharanwar:如果你遍历这样的字典,你只会遍历键,而不是键值元组。改为迭代 dict.iteritems()
【解决方案2】:

您可以像这样使用 lambda 迭代 dict:

d = {'a': 1, 'b': 2}
values = map(lambda key: d[key], d.keys())

【讨论】:

  • 严格来说,map 正在遍历字典
  • 你最好在地图中使用没有副作用的函数。
  • 值 =d.values() !!
【解决方案3】:

使用 lambda 进行字典迭代

dct = {1: '1', 2 : '2'}

使用 lambda 遍历字典:

map(lambda x : str(x[0]) + x[1], dct.iteritems())

这里 x[0] 是关键 x[1] 是值

结果: ['11', '22']

使用 lambda 过滤字典:

filter(lambda x : x[0] > 1, dct.iteritems())

结果: [(2, '2')]

【讨论】:

    【解决方案4】:

    使用普通的lambda 来迭代 Python 中的任何内容听起来非常错误。当然,最 Pythonic 的迭代序列和集合的方法是使用列表推导和生成器表达式,例如 @Andrey 提出的。

    如果面试官倾向于更多理论/计算机科学的答案,值得注意的是使用 lambdas 进行迭代很有可能,尽管我必须强调这不是 Pythonic 也没有任何用处学术练习以外的背景:

    # the legendary Y combinator makes it possible
    # to let nameless functions recurse using an indirection
    Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
    # our iterator lambda
    it = lambda f: lambda Lst: (Lst[0], f(Lst[1:])) if Lst else None
    # see it in action:
    Y(it)([1,2,3])
    => (1, (2, (3, None)))
    

    【讨论】:

      【解决方案5】:

      lambda 本身不会迭代任何东西。正如你所想,它只是定义了一个匿名函数——除了只能有一个表达式的语法规则之外,lambda 只不过是使用def 制作的类似函数。 lambda 中的代码可能会迭代某些内容,但只能以与任何其他函数可能使用的方式相同的方式(前提是它们是表达式,并且在 lambda 中有效)。

      在您提到的使用sorted 的示例中,对要排序的列表的每个元素调用键函数-但sorted 本身执行此操作,并执行迭代。当您提供一个关键功能时,sorted 会做一些与此大体相似的事情:

      def sorted(seq, key):
          decorated = [(key(elem), i) for i, elem in enumerate(seq)]
          # Sort using the normal tuple lexicographic comparisons
          decorated.sort()
          return [seq[i] for _,i in decorated]
      

      如您所见,sorted 在此处进行迭代,而不是 lambda。事实上,没有理由将键 设为 lambda - 就sorted 而言,任何函数(或任何可调用函数)都可以。


      在最低级别,只有一种方法可以在 Python 中迭代 dict(或者实际上是任何其他可迭代对象),即使用 iterator 协议。这就是 for 循环在幕后所做的事情,您也可以像这样使用 while 语句:

      it = iter(my_iterable)
      while True:
          try:
              val = next(it)
          except StopIteration:
              # Run else clause of for loop
              break
          else:
              # Run for loop body
      

      这里的 cmets 并不是严格意义上的迭代器协议的一部分,它们是 for 循环的一部分(但其中至少有一个循环体,这首先是迭代的重点)。

      其他使用可迭代对象的函数和语法(例如列表、集合和字典推导、生成器表达式或像 sumsortedsortedmax 这样的内置函数)都使用此协议,通过以下任一方式:

      • 使用 Python for 循环,
      • 执行类似于上述while 循环的操作(尤其是对于用C 编写的模块),
      • 委托给另一个函数或使用其中之一的语法片段

      可以创建一个类,使其实例变为可通过以下两种方式之一进行迭代:

      • 直接提供迭代器协议。您需要一个名为__iter__(由iter 调用)的方法,该方法返回一个迭代器。该迭代器有一个名为 __next__ 的方法(在 Python 2 中只是 next),该方法由 next 调用并返回迭代器当前位置的值并推进它(如果它已经在末尾,则引发 StopIteration );或
      • 实现部分序列协议(这意味着表现得像一个列表或元组)。对于前向迭代,以这样的方式定义__getitem__ 就足够了:执行my_sequence[0]my_sequence[1],直到my_sequence[n-1](其中n 是序列中的项目数),并且更高的索引会提高一个错误。你通常也想定义__len__,当你做len(my_sequence)时使用它。

      【讨论】:

        【解决方案6】:

        在python中迭代dict的最好方法是:

        dic ={}
        
        iter_dic = dic.iteritems().next
        iter_dic()
        ...
        iter_dic()
        

        但是你可以用 lambda func 构建它:

        iter_dic = lambda dic: dic.keys()[0],dic.pop(dic.keys()[0])
        iter_dic(dic)
        ...
        iter_dic(dic)
        

        【讨论】:

          最近更新 更多