Вставка хэша в массив

У меня есть эти хэши в качестве вывода, которые мне нужно вставить в массив без перезаписи.

output1= {:user_id=>9, :project_id=>4, :task_id=>87,  :comment=>"Test 20"}
output2 = {:user_id=>9, :project_id=>12, :task_id=>105,:comment=>"Test 21"}

Мне нужно поместить эти 2 вывода в один массив, когда я повторяю цикл. Что происходит прямо сейчас, так это то, что когда я вставляю второй вывод в массив, он также перезаписывает первый, и ниже приводится результат, который я получаю.

Entry_array=[{:user_id=>9,:project_id=>12,:task_id=>105,:comment=>"Test 21"}, 
{:user_id=>9, :project_id=>12, :task_id=>105,:comment=>"Test 21"}]

Я хочу, чтобы результат хэш-вывода1 и хэш-вывод2 был объединен. Спасибо ценю всю помощь.

Это код, который я использую

   attributes =[:user_id,:project_id,task_id,:comment]
   entry_array=[]
   output = {}

   CSV.foreach(csv_file, headers: true, converters: :date).with_index do |row,line_no|
   entry_hash= row.to_hash
   .....some code here where we get the entry_hash....
     i=0

     entry_array <<output
   end 

person Archie123    schedule 07.08.2017    source источник
comment
Покажите какой-нибудь код, пожалуйста (например, где вы «перебираете цикл»).   -  person jvillian    schedule 07.08.2017
comment
Я думаю, что нужно немного больше кода. Где определяется i? Что такое entry_hash? Что такое output? Что такое attributes?   -  person m. simon borg    schedule 07.08.2017


Ответы (3)


Причина, по которой это происходит, по крайней мере, согласно вашему коду, заключается в том, что вы используете один и тот же хэш output для каждой строки. Если вы побежали

puts entry_array.collect(&:object_id)

в конце вашего CSV-файла вы увидите, что все они являются одним и тем же объектом. Таким образом, даже если вы поместите его в массив в конце каждой строки, вы все равно модифицируете тот же объект, на который теперь указывает массив. По сути, то, что вы делаете, это

a = { hello: 'world' } # => {:hello=>"world"}
b = a                  # => {:hello=>"world"}
b[:hello] = 'there'
a                      # => {:hello=>"there"}
b                      # => {:hello=>"there"}

# storing it in an array does the same thing
output = { hello: 'world' } # => {:hello=>"world"}
array = [output]            # => [{:hello=>"world"}]
output[:hello] = 'there'
output                      # => {:hello=>"there"}
array                       # => [{:hello=>"there"}]

Чтобы исправить это, вам нужно создать новый хэш для каждой строки:

attributes = [:user_id, :project_id, :task_id, :comment]
entry_array = []

CSV.foreach(csv_file, headers: true, converters: :date).with_index do |row, line_no|
  output = { } # Instantiate here, inside the loop, so each row gets its own hash
  entry_hash = row.to_hash

  # if you need the key for something, use this
  # entry_hash.each.with_index do |(key, value), index|
  # otherwise, just iterate over each value
  entry_hash.each_value.with_index do |value, index|
    output[attributes[index]] = value.is_a?(Array) ? value.first.to_i : value
  end

  entry_array << output
end

Я изменил вашу проверку класса на is_a?, а также удалил счетчик i в пользу использования with_index вместо итерации, вы не использовали key в показанном примере, поэтому я просто использовал each_value, но оставил комментарий, показывающий, как используйте each_index с each в хэше, если вы использовали key, просто не показанный.

person Simple Lime    schedule 07.08.2017


Я не уверен, что это лучший способ осуществить свои мечты, но это способ

1) создайте свой массив

arr_of_hashes = []

2) Теперь, когда у вас есть массив, вы можете заполнить его своими хэшами.

output1= {:user_id=>9, :project_id=>4, :task_id=>87,  :comment=>"Test 20"}
output2 = {:user_id=>9, :project_id=>12, :task_id=>105,:comment=>"Test 21"}

arr_of_hashes << output1
arr_of_hashes << output2
...

3) теперь, когда вы проверите значение вашего arr_of_hashes, вы получите

[{:user_id=>9, :project_id=>4, :task_id=>87, :comment=>"Test 20"}, {:user_id=>9, :project_id=>12, :task_id=>105, :comment=>"Test 21"}]

Надеюсь, это поможет:)

Удачного взлома

CSV.foreach(csv_file, headers: true, converters: :date).with_index do |row,line_no|

 .....some code here where we get the entry_hash....

   entry_array = [] # you need to define the element first before you can add stuff to it :) 
   entry_hash.each do |key,value|
        if value.class == Array
          output[attributes[i]] = value.first.to_i
        else
          output[attributes[i]] = value
        end
         i += 1
     end
     entry_array <<output
   end 
person MZaragoza    schedule 07.08.2017