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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.