首页 > 解决方案 > 从结构化数据中选择数据,但优雅的功能方式

问题描述

显然,随着时间的推移,我思考功能的能力逐渐衰退。我在从数据集中选择子数据集时遇到问题。我可以用 hacky 命令式风格解决问题,但我相信,有一个很好的功能解决方案,不幸的是我找不到。

考虑这个数据结构(试图不简化它超出可用性):

class C
    attr_reader :attrC
    def initialize(base)
        @attrC = { "c1" => base+10 , "c2" => base+20, "c3" => base+30}
    end
end

class B
    attr_reader :attrB
    @@counter = 0
    def initialize
        @attrB = Hash.new
        @attrB["b#{@@counter}"] = C.new(@@counter)
        @@counter += 1
    end
end

class A
    attr_reader :attrA
    def initialize
        @attrA = { "a1" => B.new, "a2" => B.new, "a3" => B.new}
    end
end

它被创建为a = A.new. 完整的数据集将是

#<A: @attrA={"a1"=>#<B: @attrB={"b0"=>#<C: @attrC={"c1"=>10, "c2"=>20, "c3"=>30}>}>, 
             "a2"=>#<B: @attrB={"b1"=>#<C: @attrC={"c1"=>11, "c2"=>21, "c3"=>31}>}>, 
             "a3"=>#<B: @attrB={"b2"=>#<C: @attrC={"c1"=>12, "c2"=>22, "c3"=>32}>}>}>

这是受选择的。我只想检索BwhereattrB的 key所在的那些实例"b2"

我的hacky方式是:

result = Array.new
A.new.attrA.each do |_,va|
    result << va.attrB.select { |kb,_| kb == "b2" }
end

p result.reject { |a| a.empty?} [0]

这正是我想要的:

{"b2"=>#<C: @attrC={"c1"=>12, "c2"=>22, "c3"=>32}>}

但我相信会有一个使用 map、fold、zip 和 reduce 的单行。

标签: rubyfunctional-programming

解决方案


如果你想要一个单行:

a.attrA.values.select { |b| b.attrB.keys == %w(b2) }

这将返回B. 在您的问题中,您得到的是attrB值而不是B. 如果这就是你想要的,那就是丑陋的reduce

a.attrA.values.reduce([]) { |memo, b| memo << b.attrB if b.attrB.keys == %w(b2) ; memo }

不过,我不确定你想在这里做什么?


推荐阅读