【问题标题】:Getting a map() to return a list in Python 3.x在 Python 3.x 中获取 map() 以返回列表
【发布时间】:2010-11-21 03:51:18
【问题描述】:

我正在尝试将列表映射为十六进制,然后在其他地方使用该列表。在 python 2.6 中,这很容易:

答: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

但是,在 Python 3.1 中,上述内容返回一个地图对象。

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

如何在 Python 3.x 上检索映射列表(如上面的 A 所示)?

或者,有没有更好的方法来做到这一点?我的初始列表对象有大约 45 个项目,并且 id 喜欢将它们转换为十六进制。

【问题讨论】:

标签: python list python-3.x map-function


【解决方案1】:

这样做:

list(map(chr,[66,53,0,94]))

在 Python 3+ 中,许多迭代可迭代对象的进程本身返回迭代器。在大多数情况下,这最终会节省内存,并且应该让事情变得更快。

如果您要做的只是最终迭代此列表,则甚至无需将其转换为列表,因为您仍然可以像这样迭代 map 对象:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

【讨论】:

  • 当然,您也可以对其进行迭代:(chr(x) for x in [65,66,67,68])。它甚至不需要地图。
  • @hughdbrown 在对复杂函数、大型数据集或流进行迭代时,使用 3.1 的 map 的参数将是惰性求值。
  • @Andrew 实际上 Hugh 正在使用可以做同样事情的生成器理解。注意括号而不是方括号。
  • 当已知值为 ASCII/latin-1 的值时,替代解决方案(对于大型输入也更快)是在 C 层进行批量转换:bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1') 这使得str 更快避免对每个元素调用 Python 函数,而是只使用 C 级函数调用对所有元素进行批量转换。如果您确实需要单个字符的list,则可以将上述内容包装在list 中,但是由于str 已经是其自身字符的可迭代,因此您这样做的唯一原因是您需要可变性。
  • “参数错误”仅在 PDB 调试器中发生。见:stackoverflow.com/questions/17290314/…
【解决方案2】:

Python 3.5 中的新功能:

[*map(chr, [66, 53, 0, 94])]

感谢Additional Unpacking Generalizations

更新

一直在寻找更短的方法,我发现这个方法也有效:

*map(chr, [66, 53, 0, 94]),

解包也适用于元组。注意最后的逗号。这使它成为 1 个元素的元组。也就是相当于(*map(chr, [66, 53, 0, 94]),)

它比带有列表括号的版本短了一个字符,但在我看来,最好写,因为你从星号开始 - 扩展语法,所以我觉得它更柔软。 :)

【讨论】:

  • @Quelklef list() 看起来不那么整洁
  • @Quelklef:此外,由于不需要查找list 构造函数并调用通用函数调用机制,解包方法的速度也非常快。对于长输入,没关系;对于一个简短的,它可以产生很大的不同。使用上述代码,输入为tuple,因此不会重复重构,ipython 微基准测试显示list() 包装方法比解包方法花费大约 20% 的时间。请注意,从绝对意义上讲,我们谈论的是 150 ns,这是微不足道的,但你明白了。
  • *map()Python 3.6 上给出语法错误:can't use starred expression here。你需要把它放在list:[ *map() ]
  • @ALH 您错过了命令末尾的逗号。容易犯错误!
  • 我发现使用list其实跑得比这个快
【解决方案3】:

你为什么不这样做:

[chr(x) for x in [66,53,0,94]]

这称为列表推导。您可以在 Google 上找到大量信息,但 here's the link to the Python (2.6) documentation on list comprehensions。不过,您可能对the Python 3 documenation 更感兴趣。

【讨论】:

  • 嗯。也许需要在 python 中发布关于列表推导、生成器、map()、zip() 和许多其他快速迭代优点的一般帖子。
  • 我猜因为它更冗长,你必须编写一个额外的变量(两次)......如果操作更复杂并且你最终编写了一个 lambda,或者你还需要删除一些元素,我认为理解肯定比 map+filter 更好,但是如果你已经有了想要应用的功能,map 会更简洁。
  • +1:更易于阅读,允许您使用具有许多参数的函数
  • map(chr, [66,53,0,94]) 绝对比[chr(x) for x in [66,53,0,94]] 更简洁。
  • 比其他答案更快
【解决方案4】:

返回列表的地图功能具有节省打字的优势,尤其是在交互式会话期间。您可以定义返回列表的lmap 函数(类似于python2 的imap):

lmap = lambda func, *iterable: list(map(func, *iterable))

然后调用 lmap 而不是 map 将完成这项工作: lmap(str, x)list(map(str, x)) 短 5 个字符(在这种情况下为 30%),并且肯定比 [str(v) for v in x] 短。您也可以为filter 创建类似的函数。

对原问题有评论:

我建议重命名为 Getting map() 以在 Python 3.* 中返回一个列表,因为它适用于所有 Python3 版本。有没有办法做到这一点? – meawoppl 1 月 24 日 17:58

可以这样做,但这是一个非常糟糕的主意。只是为了好玩,您可以(但不应该)这样做:

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator

【讨论】:

    【解决方案5】:

    转换my old comment 以获得更好的可见性:对于完全不使用map 的“更好的方法”,如果您的输入已知是ASCII 序数,则转换为bytes 并解码通常要快得多,a拉bytes(list_of_ordinals).decode('ascii')。这为您提供了 str 的值,但如果您需要 list 来实现可变性等,您可以直接转换它(而且它仍然更快)。例如,在ipython 微基准测试中转换 45 个输入:

    >>> %%timeit -r5 ordinals = list(range(45))
    ... list(map(chr, ordinals))
    ...
    3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)
    
    >>> %%timeit -r5 ordinals = list(range(45))
    ... [*map(chr, ordinals)]
    ...
    3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)
    
    >>> %%timeit -r5 ordinals = list(range(45))
    ... [*bytes(ordinals).decode('ascii')]
    ...
    1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
    
    >>> %%timeit -r5 ordinals = list(range(45))
    ... bytes(ordinals).decode('ascii')
    ...
    781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
    

    如果您将其保留为str,则它需要最快map 解决方案的大约20% 的时间;即使转换回列表,它仍然不到最快map 解决方案的 40%。通过bytesbytes.decode 进行批量转换,然后批量转换回list 可以节省大量工作,但是如前所述,仅当您的所有输入都是 ASCII 序数(或某个序数)时才有效每个字符的字节数区域设置特定编码,例如latin-1)。

    【讨论】:

    • 不幸的是,您的代码在 IPython 8.0.1 中不起作用:“UsageError: Line magic function %%timeit not found。”无论如何,我更喜欢没有“魔法”的简单 Python(我会自己写)。
    • @YaroslavNikitenko: 神奇之处在于微基准测试可以轻松展示相对速度;实际代码([*bytes(ordinals).decode('ascii')]bytes(ordinals).decode('ascii'))是纯 Python。您总是可以使用timeit 模块的timeit.repeat 函数来获得相同的结果(它只是看起来比IPython 显示丑一点)。或者直接通过命令行使用它,例如python3 -mtimeit -s "ordinals = list(range(45))" "[*bytes(ordinals).decode('ascii')]".
    • @YaroslavNikitenko:嗯...根据the docs, IPython made updates to %timeit/%%timeit 在8.0 的时间范围内,它是still a documented feature,所以它应该仍然存在。让我觉得你的安装在某种程度上被破坏了。
    • (好像不能插入你的名字)。奇怪的是,我只收到了关于你最后一次提交的通知(哎呀,评论!)。无论如何,您是对的,这种方法在“行模式”下对我有效(带有一个百分号,%timeit)。不要经常使用 IPython。谢谢你的建议。我知道 timeit 模块,并且已经在脚本中使用了它(直接使用其 setup 参数调用 timeit.timeit)。
    【解决方案6】:
    list(map(chr, [66, 53, 0, 94]))
    

    map(func, *iterables) --> 映射对象 创建一个迭代器,使用来自的参数计算函数 每个迭代。当最短的迭代用完时停止。

    “制作一个迭代器”

    表示它将返回一个迭代器。

    “使用来自每个可迭代对象的参数计算函数”

    意味着迭代器的 next() 函数将获取每个可迭代对象的一个​​值,并将它们中的每一个传递给函数的一个位置参数。

    所以你从 map() 函数中得到一个迭代器,然后将它传递给 list() 内置函数或使用列表推导。

    【讨论】:

      【解决方案7】:

      除了Python 3 中的上述答案之外,我们可以简单地从map 创建一个list 的结果值作为

      li = []
      for x in map(chr,[66,53,0,94]):
          li.append(x)
      
      print (li)
      >>>['B', '5', '\x00', '^']
      

      我们可以通过另一个我被打动的例子来概括,map上的操作也可以像regex问题一样以类似的方式处理,我们可以编写函数来获取要映射的项目的list并在同时。前任。

      b = 'Strings: 1,072, Another String: 474 '
      li = []
      for x in map(int,map(int, re.findall('\d+', b))):
          li.append(x)
      
      print (li)
      >>>[1, 72, 474]
      

      【讨论】:

      • @miradulo 我想在 Python 2 中返回了一个列表,但在 Python 3 中,只返回了类型,我只是尝试以相同的格式给出。如果您认为它没有必要,也许有像我这样的人会发现它有用,这就是我添加的原因。
      • 当已经有列表推导、列表函数和解包答案时,显式 for 循环不会增加太多恕我直言。
      • @miradulo 这个答案应该被否决。愚蠢的答案下的另一条评论并没有增加太多。
      【解决方案8】:

      您可以尝试通过迭代对象中的每个项目并将其存储在不同的变量中来从地图对象中获取列表。

      a = map(chr, [66, 53, 0, 94])
      b = [item for item in a]
      print(b)
      >>>['B', '5', '\x00', '^']
      

      【讨论】:

        【解决方案9】:

        另一种选择是创建一个快捷方式,返回一个列表:

        from functools import reduce
        _compose = lambda f, g: lambda *args: f(g(*args))
        lmap = reduce(_compose, (list, map))
        
        >>> lmap(chr, [66, 53, 0, 94])
        ['B', '5', '\x00', '^']
        

        【讨论】:

          【解决方案10】:

          在 pyton3.X 中执行此操作的最佳方式

          只需一行即可完成

          #Devil
          input_list = [66, 53, 0, 94]
          out = [chr(x) for x in input_list]
          print(out)
          
          # you will get the desire output in out list
          # ['B', '5', '\x00', '^']
          
          #------------------------------
          #To retrieve your list use 'ord'
          
          original_list = [ord(x) for x in out]
          print(original_list )
          #[66, 53, 0, 94]
          

          【讨论】:

            【解决方案11】:

            使用 python 中的列表推导和基本的 map 函数实用程序,也可以做到这一点:

            chi = [x for x in map(chr,[66,53,0,94])]

            【讨论】:

            • chi 列表将包含给定元素的 ASIC 值。
            • 当您可以只使用[chr(x) for x in ...] 时,为什么要使用多余的[x for x in map(chr, ...)]?在任何使用[target for target in iterable] 的地方,只要使用list(iterable),那么使用列表推导是没有意义的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多