Group array of hashes on key and append nested array on another hash key












-2















I need to reduce an array of hashes into a single hash if that hash key matches.



my_array is an array of hashes, each of which has two keys: one an active record object, the other an array of different active record objects, similar to:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff", "more stuff", "more stuff"]
},
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff 3", "uniq stuff 2"]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I want to combine hashes by first_hash_key[:id], add each item in hash_key_two to an array, not overwrite them to get:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: [
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I can reduce the top level array and hash, and use merge, but I'm losing the individual arrays inside the hash.



I've also tried grouping by the id of the first_hash_key, and then injecting like this:



my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}


Again, I'm losing the arrays in the second_hash_key. I only get the last array listed. Without map, I get an array of each hash in the group, but the top level isn't combined.



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>["stuff 3", "uniq stuff 2"]
},
{
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]
}
]


Update
As noted by sawa and cary, there is no sense in guessing for the second_hash_key if the data is an array or array or arrays, better to always have an array of arrays. The desired output is:



 [{:first_hash_key=>{:id=>1, :title=>"my title"}, 
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]
},
{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[["interesting stuff", "uniq stuff"]]
}]









share|improve this question

























  • Where is hash_key_two?

    – sawa
    Nov 27 '18 at 9:11











  • Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

    – Cary Swoveland
    Nov 27 '18 at 9:27






  • 1





    As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

    – Cary Swoveland
    Nov 27 '18 at 9:37
















-2















I need to reduce an array of hashes into a single hash if that hash key matches.



my_array is an array of hashes, each of which has two keys: one an active record object, the other an array of different active record objects, similar to:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff", "more stuff", "more stuff"]
},
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff 3", "uniq stuff 2"]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I want to combine hashes by first_hash_key[:id], add each item in hash_key_two to an array, not overwrite them to get:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: [
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I can reduce the top level array and hash, and use merge, but I'm losing the individual arrays inside the hash.



I've also tried grouping by the id of the first_hash_key, and then injecting like this:



my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}


Again, I'm losing the arrays in the second_hash_key. I only get the last array listed. Without map, I get an array of each hash in the group, but the top level isn't combined.



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>["stuff 3", "uniq stuff 2"]
},
{
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]
}
]


Update
As noted by sawa and cary, there is no sense in guessing for the second_hash_key if the data is an array or array or arrays, better to always have an array of arrays. The desired output is:



 [{:first_hash_key=>{:id=>1, :title=>"my title"}, 
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]
},
{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[["interesting stuff", "uniq stuff"]]
}]









share|improve this question

























  • Where is hash_key_two?

    – sawa
    Nov 27 '18 at 9:11











  • Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

    – Cary Swoveland
    Nov 27 '18 at 9:27






  • 1





    As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

    – Cary Swoveland
    Nov 27 '18 at 9:37














-2












-2








-2








I need to reduce an array of hashes into a single hash if that hash key matches.



my_array is an array of hashes, each of which has two keys: one an active record object, the other an array of different active record objects, similar to:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff", "more stuff", "more stuff"]
},
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff 3", "uniq stuff 2"]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I want to combine hashes by first_hash_key[:id], add each item in hash_key_two to an array, not overwrite them to get:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: [
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I can reduce the top level array and hash, and use merge, but I'm losing the individual arrays inside the hash.



I've also tried grouping by the id of the first_hash_key, and then injecting like this:



my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}


Again, I'm losing the arrays in the second_hash_key. I only get the last array listed. Without map, I get an array of each hash in the group, but the top level isn't combined.



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>["stuff 3", "uniq stuff 2"]
},
{
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]
}
]


Update
As noted by sawa and cary, there is no sense in guessing for the second_hash_key if the data is an array or array or arrays, better to always have an array of arrays. The desired output is:



 [{:first_hash_key=>{:id=>1, :title=>"my title"}, 
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]
},
{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[["interesting stuff", "uniq stuff"]]
}]









share|improve this question
















I need to reduce an array of hashes into a single hash if that hash key matches.



my_array is an array of hashes, each of which has two keys: one an active record object, the other an array of different active record objects, similar to:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff", "more stuff", "more stuff"]
},
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: ["stuff 3", "uniq stuff 2"]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I want to combine hashes by first_hash_key[:id], add each item in hash_key_two to an array, not overwrite them to get:



my_array = [
{
first_hash_key: {id: 1, title: "my title"},
second_hash_key: [
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
},
{
first_hash_key: {id: 2, title: "my other title"},
second_hash_key: ["interesting stuff", "uniq stuff"]
}
]


I can reduce the top level array and hash, and use merge, but I'm losing the individual arrays inside the hash.



I've also tried grouping by the id of the first_hash_key, and then injecting like this:



my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}


Again, I'm losing the arrays in the second_hash_key. I only get the last array listed. Without map, I get an array of each hash in the group, but the top level isn't combined.



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>["stuff 3", "uniq stuff 2"]
},
{
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]
}
]


Update
As noted by sawa and cary, there is no sense in guessing for the second_hash_key if the data is an array or array or arrays, better to always have an array of arrays. The desired output is:



 [{:first_hash_key=>{:id=>1, :title=>"my title"}, 
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]
},
{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[["interesting stuff", "uniq stuff"]]
}]






ruby






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 28 '18 at 2:40







trh

















asked Nov 27 '18 at 1:54









trhtrh

6,10411733




6,10411733













  • Where is hash_key_two?

    – sawa
    Nov 27 '18 at 9:11











  • Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

    – Cary Swoveland
    Nov 27 '18 at 9:27






  • 1





    As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

    – Cary Swoveland
    Nov 27 '18 at 9:37



















  • Where is hash_key_two?

    – sawa
    Nov 27 '18 at 9:11











  • Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

    – Cary Swoveland
    Nov 27 '18 at 9:27






  • 1





    As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

    – Cary Swoveland
    Nov 27 '18 at 9:37

















Where is hash_key_two?

– sawa
Nov 27 '18 at 9:11





Where is hash_key_two?

– sawa
Nov 27 '18 at 9:11













Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

– Cary Swoveland
Nov 27 '18 at 9:27





Suppose my_array[1][:first_hash_key] equaled {id: 1, title: "my dog"}. How (if at all) would that change the desired result. Perhaps if two hashes have the same value of :id they have the same value of :title.

– Cary Swoveland
Nov 27 '18 at 9:27




1




1





As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

– Cary Swoveland
Nov 27 '18 at 9:37





As @sawa intimated in a comment below you are making life unnecessarily difficult for yourself by not always having the value of :second_hash_key be an array of arrays, even when it contains just one array.

– Cary Swoveland
Nov 27 '18 at 9:37












2 Answers
2






active

oldest

votes


















0














well it ain't pretty but here you go:



my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce() do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end


returns:



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]


If you're not clear how this works you should inspect the result of each line, but to summarize




  1. group by first_hash_key

  2. call transform_values to get the values at second_hash_key corresponding to each of these first_hash_key values


  3. At this point you have a hash mapping first_hash_key value to all of the corresponding values of second_hash_key. Now just have to reduce it to get the final data structure.



This pattern of group_by => transform_values => reduce is something I use all the time and is very useful. transform_values is available in rails as well as ruby 2.5 I believe.






share|improve this answer





















  • 1





    The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

    – sawa
    Nov 27 '18 at 9:18













  • Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

    – trh
    Nov 28 '18 at 2:37



















0














my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]


The receiver of Hash#values is the hash:



{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}


This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged, here the keys being 1 and 2. That block has three block variables: _ equals the common key1; o ("old") is value of the key _ in the hash being constructed and n ("new") is the value of the key _ in the hash being merged into the hash being constructed.



The expression [*o[:second_hash_key]] converts o[:second_hash_key] to an array of itself if o[:second_hash_key] is not an array and leaves o[:second_hash_key] unchanged if it is already an array. For example, [*1] #=> [1], whereas [*[1,2]] #=> [1,2].



The return value is problematic in that the value of :second_hash_key is in one case an array of arrays and in another it is simply an array. In subsequent calculations it therefore will be necessary to determine if each value is an array of arrays or just an array, and then take action accordingly. That could be done, of course, but it's messy and ugly; better to make all the values arrays of arrays. We could do that as follows.



my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]


1 The use of the underscore--a valid local variable--for the common key is to inform the reader that it is not used in the block calculation.






share|improve this answer
























  • So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

    – trh
    Nov 28 '18 at 2:40











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53491664%2fgroup-array-of-hashes-on-key-and-append-nested-array-on-another-hash-key%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














well it ain't pretty but here you go:



my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce() do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end


returns:



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]


If you're not clear how this works you should inspect the result of each line, but to summarize




  1. group by first_hash_key

  2. call transform_values to get the values at second_hash_key corresponding to each of these first_hash_key values


  3. At this point you have a hash mapping first_hash_key value to all of the corresponding values of second_hash_key. Now just have to reduce it to get the final data structure.



This pattern of group_by => transform_values => reduce is something I use all the time and is very useful. transform_values is available in rails as well as ruby 2.5 I believe.






share|improve this answer





















  • 1





    The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

    – sawa
    Nov 27 '18 at 9:18













  • Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

    – trh
    Nov 28 '18 at 2:37
















0














well it ain't pretty but here you go:



my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce() do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end


returns:



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]


If you're not clear how this works you should inspect the result of each line, but to summarize




  1. group by first_hash_key

  2. call transform_values to get the values at second_hash_key corresponding to each of these first_hash_key values


  3. At this point you have a hash mapping first_hash_key value to all of the corresponding values of second_hash_key. Now just have to reduce it to get the final data structure.



This pattern of group_by => transform_values => reduce is something I use all the time and is very useful. transform_values is available in rails as well as ruby 2.5 I believe.






share|improve this answer





















  • 1





    The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

    – sawa
    Nov 27 '18 at 9:18













  • Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

    – trh
    Nov 28 '18 at 2:37














0












0








0







well it ain't pretty but here you go:



my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce() do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end


returns:



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]


If you're not clear how this works you should inspect the result of each line, but to summarize




  1. group by first_hash_key

  2. call transform_values to get the values at second_hash_key corresponding to each of these first_hash_key values


  3. At this point you have a hash mapping first_hash_key value to all of the corresponding values of second_hash_key. Now just have to reduce it to get the final data structure.



This pattern of group_by => transform_values => reduce is something I use all the time and is very useful. transform_values is available in rails as well as ruby 2.5 I believe.






share|improve this answer















well it ain't pretty but here you go:



my_array.
group_by { |elem| elem[:first_hash_key] }.
transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
reduce() do |memo, (key, vals)|
memo + [{first_hash_key: key, second_hash_key: vals}]
end


returns:



[
{
:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[
["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]
]
}, {
:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>[
["interesting stuff", "uniq stuff"]
]
}
]


If you're not clear how this works you should inspect the result of each line, but to summarize




  1. group by first_hash_key

  2. call transform_values to get the values at second_hash_key corresponding to each of these first_hash_key values


  3. At this point you have a hash mapping first_hash_key value to all of the corresponding values of second_hash_key. Now just have to reduce it to get the final data structure.



This pattern of group_by => transform_values => reduce is something I use all the time and is very useful. transform_values is available in rails as well as ruby 2.5 I believe.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 27 '18 at 3:39

























answered Nov 27 '18 at 3:33









max pleanermax pleaner

13.9k42167




13.9k42167








  • 1





    The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

    – sawa
    Nov 27 '18 at 9:18













  • Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

    – trh
    Nov 28 '18 at 2:37














  • 1





    The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

    – sawa
    Nov 27 '18 at 9:18













  • Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

    – trh
    Nov 28 '18 at 2:37








1




1





The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

– sawa
Nov 27 '18 at 9:18







The result of your code is more consistent and makes sense, but is different from what OP wanted. For the value of :second_hash_key in the hash where [:first_hash_key][:id] == 2, the OP did not want a nested array. What OP wanted is inconsistent and makes less sense, but is not what your code returns.

– sawa
Nov 27 '18 at 9:18















Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

– trh
Nov 28 '18 at 2:37





Actually - I do want a nested array, and max's code returns a nested array - I incorrectly posted my desired return. I need to be able to iterate over the arrays from second_hash_key. I can update the question

– trh
Nov 28 '18 at 2:37













0














my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]


The receiver of Hash#values is the hash:



{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}


This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged, here the keys being 1 and 2. That block has three block variables: _ equals the common key1; o ("old") is value of the key _ in the hash being constructed and n ("new") is the value of the key _ in the hash being merged into the hash being constructed.



The expression [*o[:second_hash_key]] converts o[:second_hash_key] to an array of itself if o[:second_hash_key] is not an array and leaves o[:second_hash_key] unchanged if it is already an array. For example, [*1] #=> [1], whereas [*[1,2]] #=> [1,2].



The return value is problematic in that the value of :second_hash_key is in one case an array of arrays and in another it is simply an array. In subsequent calculations it therefore will be necessary to determine if each value is an array of arrays or just an array, and then take action accordingly. That could be done, of course, but it's messy and ugly; better to make all the values arrays of arrays. We could do that as follows.



my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]


1 The use of the underscore--a valid local variable--for the common key is to inform the reader that it is not used in the block calculation.






share|improve this answer
























  • So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

    – trh
    Nov 28 '18 at 2:40
















0














my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]


The receiver of Hash#values is the hash:



{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}


This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged, here the keys being 1 and 2. That block has three block variables: _ equals the common key1; o ("old") is value of the key _ in the hash being constructed and n ("new") is the value of the key _ in the hash being merged into the hash being constructed.



The expression [*o[:second_hash_key]] converts o[:second_hash_key] to an array of itself if o[:second_hash_key] is not an array and leaves o[:second_hash_key] unchanged if it is already an array. For example, [*1] #=> [1], whereas [*[1,2]] #=> [1,2].



The return value is problematic in that the value of :second_hash_key is in one case an array of arrays and in another it is simply an array. In subsequent calculations it therefore will be necessary to determine if each value is an array of arrays or just an array, and then take action accordingly. That could be done, of course, but it's messy and ugly; better to make all the values arrays of arrays. We could do that as follows.



my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]


1 The use of the underscore--a valid local variable--for the common key is to inform the reader that it is not used in the block calculation.






share|improve this answer
























  • So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

    – trh
    Nov 28 '18 at 2:40














0












0








0







my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]


The receiver of Hash#values is the hash:



{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}


This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged, here the keys being 1 and 2. That block has three block variables: _ equals the common key1; o ("old") is value of the key _ in the hash being constructed and n ("new") is the value of the key _ in the hash being merged into the hash being constructed.



The expression [*o[:second_hash_key]] converts o[:second_hash_key] to an array of itself if o[:second_hash_key] is not an array and leaves o[:second_hash_key] unchanged if it is already an array. For example, [*1] #=> [1], whereas [*[1,2]] #=> [1,2].



The return value is problematic in that the value of :second_hash_key is in one case an array of arrays and in another it is simply an array. In subsequent calculations it therefore will be necessary to determine if each value is an array of arrays or just an array, and then take action accordingly. That could be done, of course, but it's messy and ugly; better to make all the values arrays of arrays. We could do that as follows.



my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]


1 The use of the underscore--a valid local variable--for the common key is to inform the reader that it is not used in the block calculation.






share|improve this answer













my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>["interesting stuff", "uniq stuff"]}]


The receiver of Hash#values is the hash:



{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
:second_hash_key=>[["stuff", "more stuff", "more stuff"],
["stuff 3", "uniq stuff 2"]]},
2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
:second_hash_key=>["interesting stuff", "uniq stuff"]}}


This uses the form of Hash#update (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged, here the keys being 1 and 2. That block has three block variables: _ equals the common key1; o ("old") is value of the key _ in the hash being constructed and n ("new") is the value of the key _ in the hash being merged into the hash being constructed.



The expression [*o[:second_hash_key]] converts o[:second_hash_key] to an array of itself if o[:second_hash_key] is not an array and leaves o[:second_hash_key] unchanged if it is already an array. For example, [*1] #=> [1], whereas [*[1,2]] #=> [1,2].



The return value is problematic in that the value of :second_hash_key is in one case an array of arrays and in another it is simply an array. In subsequent calculations it therefore will be necessary to determine if each value is an array of arrays or just an array, and then take action accordingly. That could be done, of course, but it's messy and ugly; better to make all the values arrays of arrays. We could do that as follows.



my_array.each_with_object({}) do |g,h|
h.update(g[:first_hash_key][:id]=>
g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
#=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
# :second_hash_key=>[["stuff", "more stuff", "more stuff"],
# ["stuff 3", "uniq stuff 2"]]},
# {:first_hash_key=>{:id=>2, :title=>"my other title"},
# :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]


1 The use of the underscore--a valid local variable--for the common key is to inform the reader that it is not used in the block calculation.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 27 '18 at 19:13









Cary SwovelandCary Swoveland

69.8k54166




69.8k54166













  • So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

    – trh
    Nov 28 '18 at 2:40



















  • So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

    – trh
    Nov 28 '18 at 2:40

















So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

– trh
Nov 28 '18 at 2:40





So noted. I agree, too much work to guess at the data within second_hash_key - updated output required. thanks!!!!

– trh
Nov 28 '18 at 2:40


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53491664%2fgroup-array-of-hashes-on-key-and-append-nested-array-on-another-hash-key%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)