我按hash[:points]
original = [{a: "Bill", points: 4}, {b: "Will", points: 3}, {c: "Gill", points: 2}, {d: "Pill", points: 1}]
我想根据子集数组的顺序更改其元素的顺序,也按hash[:points]
排序。
subset = [{c: "Gill", points: 2}, {b: "Will", points: 1}]
子集的元素始终包含在原始元素中。但是子集的长度和顺序是随机的。它可以有任何顺序的两个,三个或四个元素。
我想将子集的顺序合并到原始数组中。这可以通过重新排序原件,或以正确的顺序重新创建原件来完成。要么会这样做。但我不想合并它们。子集中的keys
和values
并不重要,只是元素的顺序。
例如,上面的子集应该产生这个。
# Bill and Pill retain their original position
# Gill and Will swap places as per ordering of the subset
[{a: "Bill", points: 4}, {c: "Gill", points: 2}, {b: "Will", points: 3}, {d: "{Pill}", points: 1}]
此子集的另一个示例:[{c: "Gill", points: 3}, {b: "Will", points: 2}, {a: "Bill", points: 1}]
# Pill remains at index 3 since it was not in the subset
# Gill, Will, and Bill are reordered based on the order of the subset
[{c: "Gill", points: 3}, {b: "Will", points: 2}, {a: "Bill", points: 1}, {d: "Pill", points: 1}]
在过去的几个小时里,我尝试了很多东西,但我发现它比看起来更难。
答案 0 :(得分:2)
我的解决方案有两个步骤:
以下是代码:
mapped_elements = subset.map { |i| original.find { |j| j.keys == i.keys } }
result = original.map do |i|
if subset.find { |j| j.keys == i.keys }
mapped_elements.shift
else
i
end
end
对于subset = [{c: "Gill", points: 2}, {b: "Will", points: 1}]
,结果将为:
[{a: "Bill", points: 4}, {c: "Gill", points: 2}, {b: "Will", points: 3}, {d: "{Pill}", points: 1}]
对于subset = [{c: "Gill", points: 3}, {b: "Will", points: 2}, {a: "Bill", points: 1}]
,结果将为:
[{c: "Gill", points: 3}, {b: "Will", points: 2}, {a: "Bill", points: 4}, {d: "Pill", points: 1}]
答案 1 :(得分:1)
I know this sounds weird, but trust me, there is a very good reason for it.
对不起,没有办法。我认为你开始选择错误的哈希结构。我想不出为什么你会为每个人的名字创建具有不同键的哈希的任何理由。当您在操作最初选择的数据结构时遇到问题,那么您应该考虑重构数据。
teams = {
Bill: {group: "a", points: 4},
Will: {group: "b", points: 3},
Gill: {group: "c", points: 2},
Pill: {group: "d", points: 1},
}
teams_subset = {
Gill: {group: "c", points: 3},
Will: {group: "b", points: 2},
Bill: {group: "a", points: 1},
}
subset_names = teams_subset.keys
new_teams = {}
teams.each do |team, stats|
if teams_subset.include? team
next_subset_name = subset_names.shift
new_teams[next_subset_name] = teams[next_subset_name]
else
new_teams[team] = stats
end
end
p new_teams
--output:--
{:Gill=>{:group=>"c", :points=>2}, :Will=>{:group=>"b", :points=>3}, :Bill=>{:group=>"a", :points=>4}, :Pill=>{:group=>"d", :points=>1}}
甚至:
teams = [
{name: 'Bill', stats: {group: "a", points: 4}},
{name: 'Will', stats: {group: "b", points: 3}},
{name: 'Gill', stats: {group: "c", points: 2}},
{name: 'Pill', stats: {group: "d", points: 1}},
]
根据您的新发现,我只想使用准Schwarzian变换将您的数据转换为此形式:
"Bill"=>{:name=>"Bill", :points=>4}
...然后应用类似于我上面发布的代码,如下所示:
require 'set'
teams = [
{name: 'Bill', points: 4},
{name: 'Will', points: 3},
{name: 'Gill', points: 2},
{name: 'Pill', points: 1},
]
remapped_teams = {}
teams.each do |hash|
name = hash[:name]
remapped_teams[name] = hash
end
p remapped_teams
#--output:--
#{"Bill"=>{:name=>"Bill", :points=>4}, "Will"=>{:name=>"Will", :points=>3}, "Gill"=>{:name=>"Gill", :points=>2}, "Pill"=>{:name=>"Pill", :points=>1}}
teams_subset = [
{name: 'Gill', points: 3},
{name: 'Will', points: 2},
{name: 'Bill', points: 1},
]
subset_names = teams_subset.map do |hash|
hash[:name]
end
subset_names_lookup = Set.new(subset_names)
new_team_order = remapped_teams.map do |(name, hash)|
if subset_names_lookup.include? name
remapped_teams[subset_names.shift]
else
hash
end
end
p new_team_order
--output:--
[{:name=>"Gill", :points=>2}, {:name=>"Will", :points=>3}, {:name=>"Bill", :points=>4}, {:name=>"Pill", :points=>1}]
答案 2 :(得分:1)
这是另一种方法。这是基于以下理解:original
和subset
中的每个哈希包含相同的两个密钥::name
(比方说)和:points
。
<强>代码强>
def reorder(original, subset)
orig_hash = original.each_with_object({}) { |h,g| g[h[:name]] = h }
subset_names = subset.map { |h| h[:name] }
orig_hash.map { |k,v|
subset_names.include?(k) ? orig_hash[subset_names.rotate!.last] : v }
end
<强>实施例强>
original = [{name: "Bill", points: 4}, {name: "Will", points: 3},
{name: "Gill", points: 2}, {name: "Pill", points: 1}]
#1
subset = [{name: "Gill", points: 2}, {name: "Will", points: 1}]
reorder(original, subset)
#=> [{:name=>"Bill", :points=>4}, {:name=>"Gill", :points=>2},
# {:name=>"Will", :points=>3}, {:name=>"Pill", :points=>
#2
subset = [{name: "Gill", points: 3}, {name: "Will", points: 2},
{name: "Bill", points: 1}]
reorder(original, subset)
#=> [{:name=>"Gill", :points=>2}, {:name=>"Will", :points=>3},
# {:name=>"Bill", :points=>4}, {:name=>"Pill", :points=>1}]
<强>解释强>
以上original
和
subset = [{c: "Gill", points: 2}, {b: "Will", points: 1}]
从original
构建此哈希:
orig_hash = original.each_with_object({}) { |h,g| g[h[:name]] = h }
#=> {"Bill"=>{:name=>"Bill", :points=>4}, "Will"=>{:name=>"Will", :points=>3},
"Gill"=>{:name=>"Gill", :points=>2}, "Pill"=>{:name=>"Pill", :points=>1}}
以及来自:name
的{{1}}值的数组:
subsets
剩下的就是将subset_names = subset.map { |h| h[:name] }
#=> ["Gill", "Will"]
的每个k=>v
元素映射到orig_hash
{如果v
没有密钥subset_names
)或者k
subset_names
的第一个元素。由于我们无法从subset_names
中删除后者,因此我选择将数组旋转+1,然后从最后一个位置检索该值。这样,subset_names
中的下一个键将在阵列的开头正确定位。
orig_hash.map { |k,v| subset_names.include?(k) ? orig_hash[subset_names.rotate!.last] : v }
#=> [{:name=>"Bill", :points=>4}, {:name=>"Gill", :points=>2},
# {:name=>"Will", :points=>3}, {:name=>"Pill", :points=>1}]