1

I am trying to add elements to an array, and then push it to a hash. I need following output

{:jan=>"jan", :feb=>"jan", :mar=>"jan", :apr=>"jan", :cont=>["j", "a", 
 "n"]}
{:jan=>"feb", :feb=>"feb", :mar=>"feb", :apr=>"feb", :cont=>["f", "e", 
 "b"]}
{:jan=>"mar", :feb=>"mar", :mar=>"mar", :apr=>"mar", :cont=>["m", "a", 
 "r"]}
{:jan=>"apr", :feb=>"apr", :mar=>"apr", :apr=>"apr", :cont=>["a", "p", 
 "r"]}

Here is my code:

arr = ['jan', 'feb', 'mar', 'apr']
cont = []

arr.each do |f|
 cont.clear
 f.split('').each do |t|
  cont << t
 end

 hash = {jan: f, feb: f, mar: f, apr: f, cont: cont}
 trending_repos.push(hash)
end

puts trending_repos   

In the first iteration, it pushes the array that I want to see at the last. Here is the output:

{:jan=>"jan", :feb=>"jan", :mar=>"jan", :apr=>"jan", :cont=>["a", "p", 
 "r"]}
{:jan=>"feb", :feb=>"feb", :mar=>"feb", :apr=>"feb", :cont=>["a", "p", 
 "r"]}
{:jan=>"mar", :feb=>"mar", :mar=>"mar", :apr=>"mar", :cont=>["a", "p", 
 "r"]}
{:jan=>"apr", :feb=>"apr", :mar=>"apr", :apr=>"apr", :cont=>["a", "p", 
 "r"]}
4
  • You are clearing the const each iteration. This clears, adds to it, then clear... You to rearrange the order you are doing things. Commented Jul 29, 2018 at 19:17
  • @ForeverZer0yes because I need to empty array before nested each. I have figure out. Instead of cont.clear I need to move cont = [] inside first loop. Commented Jul 29, 2018 at 19:20
  • I see now, I was thinking the end for the inner-loop was the close of the outer block. :P Commented Jul 29, 2018 at 19:51
  • Clearing the array was clearing all of them, so they would all be equal to the result of the last iteration. Commented Jul 29, 2018 at 19:54

2 Answers 2

4

This is all you need to do.

keys = arr.map(&:to_sym)
  #=> [:jan, :feb, :mar, :apr]
arr.map { |s| { **keys.product([s]).to_h, cont: s.chars } }
  #=> [{:jan=>"jan", :feb=>"jan", :mar=>"jan", :apr=>"jan", :cont=>["j", "a", "n"]},
  #    {:jan=>"feb", :feb=>"feb", :mar=>"feb", :apr=>"feb", :cont=>["f", "e", "b"]},
  #    {:jan=>"mar", :feb=>"mar", :mar=>"mar", :apr=>"mar", :cont=>["m", "a", "r"]},
  #    {:jan=>"apr", :feb=>"apr", :mar=>"apr", :apr=>"apr", :cont=>["a", "p", "r"]}] 

See this article for a good discussion of Ruby's double-splat operator for hashes. In short, { **{ a: 1 }, b: 2 } #=> {:a=>1, :b=>2} is analogous to the single-splat operator for arrays: [*[1,2],3] #=> [1,2,3].

Sign up to request clarification or add additional context in comments.

2 Comments

Or arr.map { |s| {**arr.map { |k| [k.to_sym, s] }.to_h, cont: s.chars }} to avoid hardcoding.
@Amadan, good suggestion. I implemented a little differently (then edited again, unable to resist the double-splat).
1

I have figured out whats wrong with my code. I need to move declaration of array cont inside first loop. Here is correct code.

arr = ['jan', 'feb', 'mar', 'apr']

arr.each do |f|
 cont = []
 f.split('').each do |t|
   cont << t
 end

 hash = {jan: f, feb: f, mar: f, apr: f, cont: cont}
 trending_repos.push(hash)
end

1 Comment

Yes, another reference/value issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.