我有一个哈希数组:
arr = [ {:a => 1, :b => 2}, {:a => 3, :b => 4} ]
我想要达到的是:
arr.map{|x| x[:a]}.reduce(:+)
但我觉得它有点丑,或者至少没有那么优雅
arr.map(&:a).reduce(:+)
后一种方法是错误的,因为散列中没有名为a的方法。有没有更好的写map{|x| x[:a]}的方法?
a
map{|x| x[:a]}
dba5bblo1#
您可以使用Struct创建实际的对象:
MyClass = Struct.new :a, :b arr = [MyClass.new(1, 2), MyClass.new(3, 4)] arr.map(&:a).reduce(:+) #=> 4
或者,为了获得更大的灵活性,可以使用OpenStruct:
require 'ostruct' arr = [OpenStruct.new(a: 1, b: 2), OpenStruct.new(a: 3, b: 4)] arr.map(&:a).reduce(:+) #=> 4
当然,这些都可以从现有的散列构造:
arr = [{ :a => 1, :b => 2 }, { :a => 3, :b => 4 }] ss = arr.map { |h| h.values_at :a, :b }.map { |attrs| MyClass.new(*attrs) } ss.map(&:a).reduce(:+) #=> 4 oss = arr.map { |attrs| OpenStruct.new attrs } oss.map(&:a).reduce(:+) #=> 4
或者,对于更具创造性的功能性方法:
def hash_accessor attr; ->(hash) { hash[attr] }; end arr = [{ :a => 1, :b => 2 }, { :a => 3, :b => 4 }] arr.map(&hash_accessor(:a)).reduce(:+) #=> 4
snvhrwxg2#
目前还不清楚你所说的“更好”是什么意思,以及为什么你认为正确的版本是丑陋的。你喜欢这个“更好”吗?
arr.inject(0) { |sum, h| sum + h[:a] }
t98cgbkg3#
有一个办法,扩展Symbol。
Symbol
# frozen_string_literal: true class Symbol def with(*args, &) ->(caller, *rest) { caller.send(self, *rest, *args, &) } end end
然后,给定:
您可以执行以下操作:
arr.map(&:[].with(:a)).reduce(:+)
Hash#[]
:[]
Array#map
.with(*args)
3条答案
按热度按时间dba5bblo1#
您可以使用Struct创建实际的对象:
或者,为了获得更大的灵活性,可以使用OpenStruct:
当然,这些都可以从现有的散列构造:
或者,对于更具创造性的功能性方法:
snvhrwxg2#
目前还不清楚你所说的“更好”是什么意思,以及为什么你认为正确的版本是丑陋的。
你喜欢这个“更好”吗?
t98cgbkg3#
有一个办法,扩展
Symbol
。然后,给定:
您可以执行以下操作:
Hash#[]
方法。当作为:[]
(扩展)符号传递给Array#map
时,可以在此符号上调用.with(*args)
,从而有效地将参数(散列键)传递给:[]
方法。