【发布时间】:2020-02-06 13:39:49
【问题描述】:
显然,随着时间的推移,我的思考能力逐渐衰退。我在从数据集中选择子数据集时遇到问题。我可以用 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}>}>}>
取决于选择。我只想检索B 的那些实例,其中attrB 的键是"b2"。
我的老套路是:
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 的单线。
【问题讨论】:
-
从 Ruby 的角度来看,这是一个非常不优雅的数据结构。为什么不只是一个数组,或者一个带有数字键的哈希?像这样的类变量的真正问题是它们不是线程安全的,而且通常是一个丑陋的烂摊子。在各种不寻常的方向上发生了很多事情,这表明这可能是XY Problem。这里的最终目标是什么?
-
注意:Ruby 是一种区分大小写的语言,大写字母在语法上具有特定的含义。变量和方法名称应该是小写字母。大写字母表示
ClassName或CONSTANT_NAME形式的常量。 -
@tadman 感谢您对数据结构的评论。我同意这个结构相当不方便。数据结构反映了家庭自动化中心的数据模型。我使用一个 API 来检索一个相当大的 XML 树,并决定创建我的模型以尽可能地等效,以免降低我的心理稳定性。
A代表一个设备,B一个通道,C一个数据点的状态。每个类都有更多的属性和状态。我担心,如果我开始简化模型,我会降低改进软件功能方面的能力。 -
@tadman:请原谅,但我没有收到您的大写字母评论。
A、B和C是类名,以大写字母开头(嗯...),属性以小写字母开头。浏览其他代码以获得一些灵感,我猜attribA应该更好地命名为attrib_a? -
不需要在问题标题的末尾加上“(Ruby)”;这就是标签的用途。
标签: ruby functional-programming