我意识到存在很多与此类似程度不同的问题。我已经搜索了很长时间(使用:[ruby]合并散列在关键)他们和我试图解决这个问题。在进入StackOverflow之前,我甚至和同事们一起分享了我的问题。这似乎是一个独特的问题,或者我们都只是盯着它看到一个明显的答案。同时在多个级别上合并散列阵列的复杂哈希值
基本要求
- 该解决方案必须与红宝石1.8.7标准库(没有宝石)工作。请随意另外说明其他版本的Ruby的解决方案,但这样做不会自动使一个答案比另一个更好。
- 输入数据的结构不能由其提供者改变;整个数据结构按原样提供。如果需要暂时重新排列数据以提供最有效的答案,那么只要输出与下面所需的样本相匹配,就完全没问题。另外,该解决方案不能假定哈希中排序键的位置。
- 源变量不能以任何方式改变;它在运行时是不可变的(这是检查),所以结果必须提供给一个新的变量。
- 下面的示例数据是虚构的,但问题是真实的。还有其他级别的哈希数组也必须以相同的方式合并到其他键上;所以,最好的答案可以一般适用于任意级别的数据结构。
- 最好的解决方案将易于阅读,维护,并适用于任意 - 虽然类似的数据结构。它不一定是单行代码,但是如果你可以满足一行Ruby代码中的所有要求,那么对你来说就是一种荣誉。
样本数据
如果我们认为是Apache Tomcat server.xml文件作为Ruby数据结构,而不是XML的,它可以为这个问题一个很好的模拟。进一步假设默认配置在上游合并 - 在交付给您之前 - 在稍后的某个操作使用结果数据结构之前,必须合并数据。源数据看起来非常像这样:
source = {
:Server => {
:'attribute.port' => 8005,
:'attribute.shutdown' => 'SHUTDOWN',
:Listener => [
{ :'attribute.className' => 'org.apache.catalina.startup.VersionLoggerListener' },
{ :'attribute.className' => 'org.apache.catalina.core.AprLifecycleListener',
:'attribute.SSLEngine' => 'off'},
{ :'attribute.className' => 'org.apache.catalina.core.JasperListener' },
{ :'attribute.className' => 'org.apache.catalina.core.JreMemoryLeakPreventionListener' },
{ :'attribute.className' => 'org.apache.catalina.core.AprLifecycleListener',
:'attribute.SSLEngine' => 'on'}
],
:Service => [
{ :'attribute.name' => 'Catalina',
:Connector => [
{ :'attribute.port' => 8080,
:'attribute.protocol' => 'HTTP/1.1'},
{ :'attribute.port' => 8009,
:'attribute.protocol' => 'AJP/1.3'}
],
:Engine => {
:'attribute.name' => 'Catalina',
:'attribute.defaultHost' => 'localhost',
:Realm => {
:'attribute.className' => 'org.apache.catalina.realm.LockOutRealm',
:Realm => [
{ :'attribute.className' => 'org.apache.catalina.realm.UserDatabaseRealm',
:'attribute.resourceName' => 'UserDatabase'}
]
},
:Host => [
{ :'attribute.name' => 'localhost',
:'attribute.appBase' => 'webapps',
:Valve => [
{ :'attribute.className' => 'org.apache.catalina.valves.AccessLogValve',
:'attribute.directory' => 'logs'}
]
}
]
}
},
{ :'attribute.name' => 'Catalina',
:Connector => [
{ :'attribute.port' => 8080,
:'attribute.protocol' => 'HTTP/1.1',
:'attribute.secure' => true,
:'attribute.scheme' => 'https',
:'attribute.proxyPort' => 443}
]
},
{ :'attribute.name' => 'JSVCBridge',
:Connector => [
{ :'attribute.port' => 8010,
:'attribute.protocol' => 'HTTP/2'}
]
},
{ :'attribute.name' => 'Catalina',
:Engine => {
:Host => [
{ :'attribute.name' => 'localhost',
:Valve => [
{ :'attribute.className' => 'org.apache.catalina.valves.RemoteIpValve',
:'attribute.internalProxies' => '*',
:'attribute.remoteIpHeader' => 'X-Forwarded-For',
:'attribute.protocolHeader' => 'X-Forwarded-Proto',
:'attribute.protocolHeaderHttpsValue' => 'https'}
]
}
]
}
}
]
}
}
所面临的挑战是从它产生这样的结果:
result = {
:Server => {
:'attribute.port' => 8005,
:'attribute.shutdown' => 'SHUTDOWN',
:Listener => [
{ :'attribute.className' => 'org.apache.catalina.startup.VersionLoggerListener' },
{ :'attribute.className' => 'org.apache.catalina.core.AprLifecycleListener',
:'attribute.SSLEngine' => 'on'},
{ :'attribute.className' => 'org.apache.catalina.core.JasperListener' },
{ :'attribute.className' => 'org.apache.catalina.core.JreMemoryLeakPreventionListener' },
],
:Service => [
{ :'attribute.name' => 'Catalina',
:Connector => [
{ :'attribute.port' => 8080,
:'attribute.protocol' => 'HTTP/1.1',
:'attribute.secure' => true,
:'attribute.scheme' => 'https',
:'attribute.proxyPort' => 443},
{ :'attribute.port' => 8009,
:'attribute.protocol' => 'AJP/1.3'}
],
:Engine => {
:'attribute.name' => 'Catalina',
:'attribute.defaultHost' => 'localhost',
:Realm => {
:'attribute.className' => 'org.apache.catalina.realm.LockOutRealm',
:Realm => [
{ :'attribute.className' => 'org.apache.catalina.realm.UserDatabaseRealm',
:'attribute.resourceName' => 'UserDatabase'}
]
},
:Host => [
{ :'attribute.name' => 'localhost',
:'attribute.appBase' => 'webapps',
:Valve => [
{ :'attribute.className' => 'org.apache.catalina.valves.AccessLogValve',
:'attribute.directory' => 'logs'},
{ :'attribute.className' => 'org.apache.catalina.valves.RemoteIpValve',
:'attribute.internalProxies' => '*',
:'attribute.remoteIpHeader' => 'X-Forwarded-For',
:'attribute.protocolHeader' => 'X-Forwarded-Proto',
:'attribute.protocolHeaderHttpsValue' => 'https'}
]
}
]
}
},
{ :'attribute.name' => 'JSVCBridge',
:Connector => [
{ :'attribute.port' => 8010,
:'attribute.protocol' => 'HTTP/2'}
]
}
]
}
}
问题
我们需要source
成为result
。为了达到这个目的,:Listener
被attribute.className
合并; :Service
合并attribute.name
; :Connector
的结果数组合并为attribute.port
;等等。在数据结构中确定哈希数组的位置和每个要合并的关键点应该很容易地提供给解决方案。
这个问题的真正本质是找到一种通用的解决方案,它可以应用于像这样的复杂数据结构的多个任意级别,通过提供的密钥合并哈希数组,并生成合并后的结果提供位置和密钥对。
非常感谢您对本问题所持的时间和兴趣。根据您是基于散列的定数组中第一项的值合并散列假设
什么规则决定了以下方面的变化:听众?是否仅仅是在一个哈希数组中,如果密钥被复制,那么该密钥的最新实例是唯一保留的实例?如果是的话为什么“attribute.className sill会在结果中出现两次? –
对于这个问题,所有的数组哈希都必须在键上进行合并,以使得后面的Hashes中的值覆盖之前的Hashes。': Listener'''Hashes'在'attribute.className'上合并,所以'attribute.SSLEngine'在结果中'org.apache.catalina.core.AprLifecycleListener'处于'on'。'attribute.className'值在':Listeners'的两个幸存元素;只有'org.apache.catalina.core.AprLifecycleListener'需要合并。 – seWilliam
你可以在一个更复杂的结构的例子中加入你可能应用该方法吗? –