0

我想mapcar在 Ruby 中实现 Lisp。

如意语法:

mul = -> (*args) { args.reduce(:*) }

mapcar(mul, [1,2,3], [4,5], [6]) would yield [24, nil, nil].

这是我能想到的解决方案:

arrs[0].zip(arrs[1], arrs[2]) => [[1, 4, 6], [2, 5, nil], [3, nil, nil]]

然后我可以:

[[1, 4, 6], [2, 5, nil], [3, nil, nil]].map do |e| 
  e.reduce(&mul) unless e.include?(nil)
end

=> [24, nil, nil]

但我被困在这zip部分。如果输入为[[1], [1,2], [1,2,3], [1,2,3,4]],则该zip部分需要更改为:

arrs[0].zip(arrs[1], arrs[2], arrs[3])

对于两个输入数组,我可以这样写:

def mapcar2(fn, *arrs)
  return [] if arrs.empty? or arrs.include? []
  arrs[0].zip(arrs[1]).map do |e|
    e.reduce(&fn) unless e.include? nil
  end.compact
end

但我不知道如何超越两个以上的数组:

def mapcar(fn, *arrs)
  # Do not know how to abstract this
  # zipped = arrs[0].zip(arrs[1], arrs[2]..., arrs[n-1])
  # where n is the size of arrs
  zipped.map do |e| 
    e.reduce(&fn) unless e.include?(nil)
  end.compact
end

有人有建议吗?

4

2 回答 2

1

如果我正确地回答了您的问题,您只需要:

arrs = [[1,2], [3,4], [5,6]]
zipped = arrs[0].zip(*arrs[1..-1])
# => [[1, 3, 5], [2, 4, 6]] 

或者更好的选择,IHMO:

zipped = arrs.first.zip(*arrs.drop(1))

如果里面的所有数组arrs都具有相同的长度,则可以使用以下transpose方法:

arrs = [[1,2], [3,4], [5,6]]
arrs.transpose
# => [[1, 3, 5], [2, 4, 6]] 
于 2013-08-08T14:53:50.560 回答
0

根据 toro2k,Ruby 中 mapcar 的一种可能实现:

def mapcar(fn, *arrs)
  return [] if arrs.empty? or arrs.include? []
  transposed = if arrs.all? { |a| arrs.first.size == a.size }
                 arrs.transpose
               else
                 arrs[0].zip(*arrs.drop(1))
               end
  transposed.map do |e|
    e.collect(&fn) unless e.include? nil
  end.compact!
end
于 2014-05-11T14:05:45.933 回答