Динамически создавать массивы в Ruby - PullRequest
5 голосов
/ 02 декабря 2009

Есть ли способ динамически создавать массивы в Ruby? Например, предположим, что я хотел просмотреть цикл книг, введенных пользователем:

books = gets.chomp

Пользовательские данные:

"The Great Gatsby, Crime and Punishment, Dracula, Fahrenheit 451,
Pride and Prejudice, Sense and Sensibility, Slaughterhouse-Five, 
The Adventures of Huckleberry Finn"

Я превращаю это в массив:

books_array = books.split(", ")

Теперь для каждой книги, введенной пользователем, я бы хотел, чтобы Ruby создал массив. Псевдокод для этого:

 x = 0

 books_array.count.times do
    x += 1
    puts "Please input weekly sales of #{books_array[x]} separated by a comma."
    weekly_sales = gets.chomp.split(",")
 end

Очевидно, это не работает. Это просто переопределит weekly_sales снова и снова. Есть ли способ достичь того, чего я добиваюсь, и с каждым циклом метода .times создавать новый массив?

Ответы [ 6 ]

7 голосов
/ 02 декабря 2009
weekly_sales = {}
puts 'Please enter a list of books'
book_list = gets.chomp
books = book_list.split(',')

books.each do |book|
  puts "Please input weekly sales of #{book} separated by a comma."
  weekly_sales[book] = gets.chomp.split(',') 
end

В ruby ​​существует понятие хэша, который представляет собой пару ключ / значение. В этом случае weekly_sales - это хеш, мы используем имя книги в качестве ключа и массив в качестве значения.

Небольшое изменение, которое я сделал в вашем коде, вместо того, чтобы делать books.count.times, чтобы определить цикл, а затем разыменовать элементы массива со счетчиком, каждый из которых является гораздо более приятным способом перебора коллекции.

2 голосов
/ 02 декабря 2009

Команда "push" добавит элементы в конец массива.

Ruby Docs-> Array-> push

1 голос
/ 02 декабря 2009

Так или иначе, вам нужна более мощная структура данных.

Ваш пост тяготеет к мысли, что weekly_sales будет массивом, параллельным массиву books. Недостаток этого подхода заключается в том, что вы должны поддерживать параллельность этих двух массивов самостоятельно.

Несколько лучшее решение - использовать название книги в качестве ключа к хэшу массивов, как предлагалось в нескольких ответах. Например: weekly_sales['Fahrenheit 451'] будет содержать массив данных о продажах для этой книги. Этот подход зависит от уникальности названий книг и имеет другие недостатки.

Более надежный подход, который вы могли бы рассмотреть, заключается в объединении информации о каждой книге в один пакет.

В самом простом конце спектра будет список хэшей. Каждая книга будет самостоятельной единицей по следующим направлениям:

books = [
    {
        'title' => 'Fahrenheit 451',
        'sales' => [1,2,3],
    },
    {
        'title' => 'Slaughterhouse-Five',
        'sales' => [123,456],
    },
]

puts books[1]['title']

На другом конце спектра будет создан надлежащий Book класс.

И промежуточный подход заключается в использовании Struct (или OpenStruct), который занимает среднее место между хэшами и полномасштабными объектами. Например:

# Define the attributes that a Book will have.
Book = Struct.new(:title, :weekly_sales)
books = []

# Simulate some user input.
books_raw_input = "Fahrenheit 451,Slaughterhouse-Five\n"
sales_raw_input = ['1,2,3', '44,55,66,77']
books_raw_input.chomp.split(',').each do |t|
    ws = sales_raw_input.shift.split(",")
    # Create a new Book.
    books.push Book.new(t, ws)        
end

# Now each book is a handy bundle of information.
books.each do |b|
    puts b.title
    puts b.weekly_sales.join(', ')
end
0 голосов
/ 02 декабря 2009
result = "The Great Gatsby, Crime and Punishment, Dracula, Fahrenheit 451,
  Pride and Prejudice, Sense and Sensibility, Slaughterhouse-Five, 
  The Adventures of Huckleberry Finn".split(/,\s*/).map do |b|
    puts "Please input weekly sales of #{b} separated by a comma."
    gets.chomp.split(',') # .map { |e| e.to_i }
end
p result

Удалите комментарий, если хотите, чтобы входные строки были преобразованы в числа

0 голосов
/ 02 декабря 2009

Это решение предполагает, что никогда не будет повторяющегося названия книги. Я полагаю, это довольно безопасно, да?

input = "A list of words"
hash = {}
input.split(/\s+/).collect { |word| hash[word] = [] }

# Now do whatever with each entry
hash.each do |word,ary|
   ary << ...
end
0 голосов
/ 02 декабря 2009

Готовы ли вы получить массив массивов? В котором это может быть полезно:

book_sales = books_array.collect do |book|
  puts "Please input weekly sales of #{books_array[0]} separated by a comma."
  gets.chomp.split(",").collect{ |s| s.to_i }
end

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

book_sales = books_array.inject({}) do |hash, book|
  puts "Please input weekly sales of #{books_array[0]} separated by a comma."
  weekly_sales = gets.chomp.split(",").collect{ |s| s.to_i }
  hash[book] = weekly_sales
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...