【问题标题】:Array#each vs. Array#mapArray#each 与 Array#map
【发布时间】:2011-07-12 08:47:41
【问题描述】:
hash = { "d" => [11, 22], "f" => [33, 44, 55] }

# case 1
hash.map {|k,vs| vs.map {|v| "#{k}:#{v}"}}.join(",")
=> "d:11,d:22,f:33,f:44,f:55"

# case 2
hash.map {|k,vs| vs.each {|v| "#{k}:#{v}"}}.join(",")
=> "11,22,33,44,55"

唯一的区别是案例 1 使用 vs.map,案例 2 使用 vs.each

这里发生了什么?

【问题讨论】:

    标签: ruby arrays enumerable


    【解决方案1】:

    当您使用映射到哈希时,它会隐式地将哈希转换为数组,因此您有

    [["d", [11, 22]], ["f", [33, 44, 55]]]
    

    vs.each{...} 只给你最后一次评估,即 [11, 22] for ["d", [11, 22]] 和 [33, 44, 55] for ["f ", [33, 44, 55]]。所以在最后一次加入之前,你有

    [[11, 22], [33, 44, 55]]
    

    【讨论】:

      【解决方案2】:

      Array#each 为数组的每个元素执行给定的块,然后返回数组本身。

      Array#map 也为数组的每个元素执行给定的块,但返回一个新数组,其值是块的每次迭代的返回值。

      例子:假设你有一个这样定义的数组:

      arr = ["tokyo", "london", "rio"]
      

      然后尝试执行each:

      arr.each { |element| element.capitalize }
      # => ["tokyo", "london", "rio"]
      

      注意返回值只是同一个数组。 each 块内的代码被执行,但不返回计算值;并且由于代码没有副作用,所以这个例子没有做任何有用的工作。

      相比之下,调用数组的map方法返回一个新数组,其元素是每轮执行map块的返回值:

      arr.map { |element| element.capitalize }
      # => ["Tokyo", "London", "Rio"]
      

      【讨论】:

      • 完美的答案可以理解。只是一个.. 免责声明:如果您过度使用 map 函数的返回值,您可能会浪费大量内存。
      【解决方案3】:

      side effects 相同,这给您的逆向工程增加了一些混乱。

      是的,两者都对数组进行迭代(实际上,对任何与Enumerable 混合的东西都进行了迭代),但map 将返回一个由块结果组成的数组,而each 将只返回原始数组。

      each 的返回值只是原始数组,在 Ruby 代码中很少使用,但mapmost important functional tools 之一。

      map 所做的是返回一个数组,其中包含传递的块或命名方法的结果。例如:

          2.2.3 :001 > [:how, :now, :brown, :cow].map &:to_s
       => ["how", "now", "brown", "cow"]
      

      在这种情况下,我没有传递一个块,而只是传递了一个 Symbol,但是 class Symbol 对象有一个 to_proc 方法,这将导致:

      [:how.to_s, :now.to_s, ...]
      

      顺便说一句,您可能很难找到文档,因为 mapEnumerable 中的一种方法,而 each (需要的一种方法Enumerable 模块)是 Array 中的一个方法。

      作为一个琐事说明:map 实现基于 each

      【讨论】:

        【解决方案4】:

        .each 返回您最初提供的相同数组:

        [1,2,3].each { |i| i + 1 }
        #=> [1,2,3]
        

        .map 从每个块调用的结果中返回一个新数组:

        [1,2,3].map { |i| i + 1 }
        #=> [2,3,4]
        

        【讨论】:

          【解决方案5】:

          这里快速演示地图与每个地图的不同之处

          a = ["a", "b", "c"];
          #Array.map
          p a.map {|item| "map_" + item}
          #prints ["map_a", "map_b", "map_c"]
          
          #Array.each
          p a.each {|item| "map_" + item}
          #prints ["a", "b", "c"]
          

          您会看到 map 返回 ["map_a", "map_b", "map_c"] 而每个只是迭代但返回原始数组:["a", "b", "c"]

          因此 each 用于处理数组,而 map 用于处理处理后的数组。

          【讨论】:

            【解决方案6】:

            Array#each 方法返回相同的数组

            a = [1,2,3,4,5]
            a.object_id #70284994490700
            
            b = a.each {|n| n + 2}
            p b #[1,2,3,4,5]
            b.object_id #70284994490700 <<--- it's the same as a
            

            Array#map 方法返回一个新数组

            c = [1,2,3,4,5]
            c.object_id #70219117705860
            
            d = c.map {|n| n + 2}
            p d #[3,4,5,6,7]
            d.object_id #70284994343620  <<---- it's different than c
            

            【讨论】:

              【解决方案7】:

              您也可以使用 map 和 bang map! 来更改源数组

              【讨论】:

              • 这不是问题的答案。问题是关于each 之间的区别,它执行给定的块并返回原始数组;和map,它返回一个数组,其中执行块的结果作为值
              猜你喜欢
              • 2011-03-19
              • 2022-12-28
              • 1970-01-01
              • 2016-09-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-05-20
              • 1970-01-01
              相关资源
              最近更新 更多