Передача элементов из одного массива в другой, генерирование CSV - PullRequest
0 голосов
/ 12 июня 2018

Я пытаюсь написать программу на Ruby, которая позволяет одному массиву получать информацию из другого массива.По сути, у меня есть многомерный массив, называемый "student_array", который содержит информацию о нескольких учениках

student_array = [["Mike", 13, "American", "male"], 
["Grace", 12, "Canadian", "female"],
["Joey", 13, "American", "male"],
["Lily", 13, "American", "female"]
]

Я также инициализировал два других массива, которые будут считать национальности:

nationality_array = Array.new
nationality_count = Array.new

Цельэта программа предназначена для циклического перемещения по массиву студентов, подсчета разных национальностей студентов и создания файла CSV, который будет содержать заголовки разных национальностей и подсчет для каждого из них.

Ожидаемый выходной файл.csv

American, Canadian
3, 1

Вот код, который у меня есть до сих пор

student_array.each do |student|
    #pushes the nationality string into the nationality array
    nationality_array.push(student[2])   
end

, поэтому на данный момент национальность_array должна выглядеть следующим образом:

nationality_array = ["American", "Canadian", "American", "American"];
nationality_array.uniq = ["American", "Canadian"];

Итак, у меня будет два заголовка -«Американец» и «Канадец»

Теперь мне нужен способ, чтобы просмотреть цикл student_array, подсчитать каждый экземпляр «американца» и «канадца» и каким-то образом присвоить его обратно в массив национальности.Мне трудно представить, как это сделать.Это то, что у меня пока есть -

american_count = 0;
canadian_count = 0;

student_array.each do |student|
    if student[2] = "American"
        american_count++
    elsif student[2] = "Canadian"
        canadian_count++
    end
end

nationality_count.push(american_count);
nationality_count.push(canadian_count);

Хорошо, теперь у меня есть эти значения в массиве nationality_count, но как я могу передать их в CSV, убедившись, что они назначены на нужные заголовки?У меня такое ощущение, что мой код очень неуклюжий и может быть гораздо более упорядоченным.

Возможно, это выглядело бы примерно так?

CSV.open("output/redemptions.csv", "wb") do |csv|
    csv << [nationality_array]
    csv << [nationality_count]
end

Может ли кто-нибудь рассказать о более чистомспособ пойти об этом?

Ответы [ 3 ]

0 голосов
/ 12 июня 2018

Array # group_by в ядре Ruby и Hash # transform_values ​​ в ActiveSupport - два очень универсальных метода, которые можно использовать здесь:

require 'active_support/all'
require 'csv'

student_array = [
  ["Mike", 13, "American", "male"], 
  ["Grace", 12, "Canadian", "female"],
  ["Joey", 13, "American", "male"],
  ["Lily", 13, "American", "female"]
]

counts = student_array.group_by { |attrs| attrs[2] }.transform_values(&:length)
# => => {"American"=>3, "Canadian"=>1}

CSV.open("output/redemptions.csv", "wb") do |csv|
    csv << counts.keys
    csv << counts.values
end

puts File.read "output/redemptions.csv"
# => American,Canadian
#    3,1

.group_by { |attrs| attrs[2] }превращает массив в хеш, где ключи - это уникальные значения для attrs[2], а значения - список элементов, которые имеют этот attrs[2].На этом этапе вы можете использовать transform_values, чтобы превратить эти значения в числа, представляющие их длину (то есть, сколько элементов имеют этот конкретный attrs[2]).Затем ключи и значения могут быть извлечены из хеша в виде отдельных массивов.

0 голосов
/ 12 июня 2018

Вы можете использовать Hash для группировки счетчиков по национальности вместо разных массивов.

nationalities_count = student_array.each_with_object(Hash.new(0)) do |student, hash| 
  nationality = student[2]
  hash[nationality] += 1
end

Это даст вам хэш, который будет выглядеть как

{ "American" => 2, "Canadian" => 1 }

Youзатем можно использовать Hash#to_a и Array#transpose примерно так:

hsh = { "American" => 2, "Canadian" => 1 }
 => {"American"=>2, "Canadian"=>1}
2.4.2 :002 > hsh.to_a
 => [["American", 2], ["Canadian", 1]]
2.4.2 :003 > hsh.to_a.transpose
 => [["American", "Canadian"], [2, 1]]

Наконец, для вывода файла CSV все, что вам нужно сделать, это записать массивы в файл

nationalities_with_count = hash.to_a.transpose
CSV.open("output/redemptions.csv", "wb") do |csv|
  csv << nationalities_with_count[0]
  csv << nationalities_with_count[1]
end
0 голосов
/ 12 июня 2018

Вам даже не нужен инструмент CSV:

result =
  student_array.
     map { |a| a[2] }.            # get nationalities
     group_by { |e| e }.          # hash
     map { |n, c| [n, c.count] }. # map values to count
     transpose.                   # put data in rows
     map { |row| row.join ',' }.  # join values in a row
     join($/)                     # join rows
#⇒ American,Canadian
#  3,1

Теперь у вас есть строка, которая является допустимой CSV, просто выплюните ее в файл.

...