【问题标题】:Reverse a mult dimensional array - functional programming style反转多维数组 - 函数式编程风格
【发布时间】:2016-11-25 13:23:59
【问题描述】:

想出一种在 Ruby 中反转多维(偶数维)数组的功能性方法让我很吃惊。 输入:[[1, 2, 3], [4, 5, 6], [7, 8, 9]] 输出:[[7, 4, 1], [8, 5, 2], [9, 6, 3]]

此迭代解决方案有效。

def reverse(arr)
  size = arr.length
  output = Array.new(size) { Array.new(size,0) }
  arr.reverse.each_with_index do |a, i|
    a.each_with_index do |a, j|
      output[j][i] = a
    end
  end
  output
end

任何人都知道如何使用更多的函数式编程风格而不参考显式索引?

【问题讨论】:

    标签: arrays ruby multidimensional-array collections functional-programming


    【解决方案1】:

    如果array 是您的输入,那么它就像

    result = array.transpose.map(&:reverse)
    

    如果我正确理解了您想要的输出。 ;)

    详细说明一下:Array#transpose 基本上沿主对角线“镜像”二维数组:

    transposed = array.transpose  #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
    

    您似乎只希望所有行都反转,这是通过调用 map 来处理的:

    result = transposed.map(&:reverse)  #=> [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
    

    map(&:reverse) 语法只是map { |a| a.reverse } 的简写,由this 方法启用。

    手工操作

    在我最初的回答之后,在 cmets 中发现 OP 实际上是在 transpose 的功能实现之后。这是我想出的:

    def transpose(a)
      (0...a[0].length).map { |i|
        (0...a.length).map { |j| a[j][i] }
      }
    end
    

    虽然 this 确实引用了显式索引,但它是一个由其他纯函数组成的纯函数,因此它至少符合 my 函数的定义。 ;)

    【讨论】:

    • 不错的答案。包含Array#transpose 的链接或快速演示其工作原理会很有帮助。
    • 这是正确的输出,当然也是客户端代码的好方法。仔细想想,我真正的好奇心是寻找一种功能性的方式来编写 Array#transpose。
    • 你是对的@sagarpandya82,我详细说明了一点,感谢您的反馈。
    • @radlab 也为你添加了一些东西。
    • 朱利安,你提出了一个重要问题。我的观点是,以最 Rubyish 的方式编写代码总是更好。是的,读者可能需要练习一下灰色的小格子才能理解你写的东西,但是他们会学到一些关于语言力量的新东西,而不是钝的 sn-p。随着练习,越来越多的 Rubyish 方式将进入潜意识,使其更容易理解和更快地阅读。
    【解决方案2】:
    ar =  [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    ar.reverse.transpose # => [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
    

    【讨论】:

      【解决方案3】:
      arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
      
      arr_rev = arr.reverse
        #=> [[7, 8, 9], [4, 5, 6], [1, 2, 3]] 
      arr_rev.first.zip *arr_rev[1..-1]
        #=> [[7, 4, 1], [8, 5, 2], [9, 6, 3]] 
      

      我相信这满足functional programming的要求。

      步骤:

      arr_rev = arr.reverse
         #=> [[7, 8, 9], [4, 5, 6], [1, 2, 3]] 
      arr_rev.first.zip(arr_rev[1..-1])
         #=> [7, 8, 9].zip(*[[4, 5, 6], [1, 2, 3]])
         #.    [7, 8, 9].zip([4, 5, 6], [1, 2, 3])
         #.    [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
      

      Enumerable#zip

      【讨论】:

      • 您能解释一下zip(*arr_rev) 部分的工作原理吗?
      • @sagarpandya82,请查看我的编辑(我应该在没有被询问的情况下提供)。
      • 是的,我真的需要这里的步骤,谢谢。我从没见过* 是这样使用的,如果我没记错的话,它似乎可以起到防泼溅的作用?
      • 不,这是 splat 的正常用法:它用元素列表替换数组。
      • 啊这就是anti-splat的意思。无论如何已经为我清理了一切,谢谢。
      猜你喜欢
      • 2019-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 2022-11-30
      • 2010-11-08
      相关资源
      最近更新 更多