Создание и ввод данных во вложенные массивы - Ruby - PullRequest
0 голосов
/ 08 мая 2019

Я пытаюсь создать программу, которая берет имена и добавляет их в массивы. Хитрость в том, что мне нужно хранить их во вложенных массивах, поэтому я спрашиваю у пользователя число - это определяет количество групп. Затем у пользователя запрашиваются имена - они должны быть отсортированы как таковые ...

  • В качестве примера представьте, что есть три группы.
    • Первый человек входит в первую группу.
    • Второй человек входит во вторую группу.
    • Третье лицо входит в третью группу.
    • Четвертый человек входит в первую группу.
    • Пятый человек входит во вторую группу.
    • и т.д.

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

groups = []

#enter the number of groups
puts "give me a number"
count = gets.to_i

while true do

puts 'Give me a name'
user_input = gets.chomp
groups.push(user_input)
groups.delete("stop")

if user_input == "stop"

puts "Give me a group number"
puts groups[gets.to_i]

#puts'es the names from that group

break

end
end

Это не похоже на миллион миль, но я не совсем уверен, куда я иду с этим.

count = 3
user_input = ["joe","sally","frank"]

groups = Array.new(count) {Array.new(user_input)}

Любая помощь будет очень признательна, очень нова для этого

Ответы [ 2 ]

2 голосов
/ 08 мая 2019

Прежде всего, вам нужно создать вложенный массив на основе заданного числа:

puts 'Enter number of groups'
count = gets.to_i
groups = Array.new(count) { [] }

Если пользователь введет 3 , у вас будет массив, содержащий 3 других массива:

groups = Array.new(3) { [] }
#=> [[], [], []]

Важно использовать блочную форму для Array.new, поэтому каждый внутренний массив является отдельным экземпляром. (см. "Общие ошибки" в документации)

Имея вложенную структуру, мы можем добавлять имена к внутренним массивам. Либо, используя переменную "counter" i и нажав group[i]:

puts 'Enter names or "stop" when done'

i = 0                  # start at 0
loop do
  user_input = gets.chomp
  break if user_input == 'stop'
  groups[i].push(user_input)

  if i < count - 1
    i += 1             # increment
  else
    i = 0              # start over
  end
end

Или - намного элегантнее - через cycle:

puts 'Enter names or "stop" when done'

groups.cycle do |group|
  user_input = gets.chomp
  break if user_input == 'stop'
  group.push(user_input)
end
0 голосов
/ 09 мая 2019

Получив количество групп, скажем

ngroups = 3

код предложит пользователю ввести серию имен, а затем "stop", когда у пользователя больше нет имен для ввода. Предположим, что пользователь вводит следующие строки в указанном порядке:

"Lucy\n", "Hank\n", "Billy-Bob\n", "Trixie\n", "Veronica\n", "Roxy\n",
"Norm\n", "Herb\n", "stop\n" 

Мы можем создать нужный массив с помощью следующего кода:

0.step.with_object(Array.new(ngroups) { [] }) do |i,a|
  print 'Please enter a name or "stop" if finished: '
  reply = gets.chomp
  break a if reply == "stop"
  a[i % ngroups] << reply     
end
  #=> [["Lucy", "Trixie", "Norm"], ["Hank", "Veronica", "Herb"],
  #    ["Billy-Bob", "Roxy"]]

Обратите внимание, что я не просил пользователя вводить группу для каждого имени. Это потому, что вы сказали, что имена должны присваиваться группам в порядке групп, возобновляясь с первой группой после каждого присвоения имени последней группе.

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

Числовой # шаг , перечислитель

enum0 = 0.step #=> (0.step)

Если вы изучите документацию для этого метода, вы увидите, что 0.step без блока возвращает перечислитель, который является экземпляром класса Перечислитель . Перечислители очень важны в Ruby. Они генерируют значения, которые могут быть переданы другим методам или заблокированы. Здесь enum0 генерирует следующую последовательность:

enum0.next #=> 0
enum0.next #=> 1
enum0.next #=> 2

... до бесконечности . См. Перечислитель # следующий .

* +1034 * Аналогично,
e = 21.step(by: -3) #=> (21.step(by: -3)) 
e.next #=> 21 
e.next #=> 18 

e = 2.34.step #=> (2.34.step) 
e.next #=> 2.34 
e.next #=> 3.34 

Enumerator # with_object

На самом деле нам не нужно использовать этот метод. Вместо этого мы могли бы написать следующее, что дает тот же результат:

a = []
0.step do |i|
  print 'Please enter a name or "stop" if finished: '
  reply = gets.chomp
  break a if reply == "stop"
  a[i % ngroups] << reply     
end
a

Как видите, использование each_object просто сохраняет две строки кода: a = [] и a в конце. 1 . Этот метод и его двоюродный брат Enumerable # each_with_object , которые широко используются программистами Ruby, на самом деле довольно просты.

Другой перечислитель

Следующее у нас есть:

enum1 = enum0.with_object(Array.new(ngroups) { [] })
  #=> #<Enumerator: (0.step):with_object([[], [], []])>

Как видно из возвращаемого значения для enum1, enum1 можно рассматривать как составной перечислитель , хотя в Ruby такой формальной концепции нет. Давайте посмотрим, какие значения генерирует этот перечислитель:

enum1.next #=> [0, [[], [], []]] 
enum1.next #=> [1, [[], [], []]] 
enum1.next #=> [2, [[], [], []]] 

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

Если бы мы хотели, мы могли бы теперь написать исходный код следующим образом 1

enum1.each do |i,a|
  print 'Please enter a name or "stop" if finished: '
  reply = gets.chomp
  break a if reply == "stop"
  a[i % ngroups] << reply     
end

См. Перечислитель # каждый .

Передача элементов, сгенерированных enum1 в блок

Когда первый элемент генерируется и передается в блок, переменным блока i и a присваиваются следующие значения:

i, a = enum1.next #=> [0, [[], [], []]] 
i #=> 0 
a #=> [[], [], []]   

Процесс разбиения массива, возвращаемого enum1.next, на его компоненты называется декомпозиция массива . Это мощный и ценный инструмент.

Теперь мы можем выполнять операции блока.

print 'Please enter a name or "stop" if finished: '
reply = "Lucy" # = gets.chomp
break a if reply == "stop" # do not break
a[i % ngroups] << reply     
  #=> a[0 % 3] << "Lucy"
  #=> a[0] << "Lucy"
  #=> ["Lucy"]

Далее enum1 генерирует его второе значение и передает его в блок, значения присваиваются переменным блока и выполняются операции блока.

i, a = enum1.next #=> [1, [["Lucy"], [], []]] 
i #=> 1 
a #=> [["Lucy"], [], []]   

Обратите внимание, что a был обновлен для отображения "Lucy", добавленного к a[0]. Продолжая,

print 'Please enter a name or "stop" if finished: '
reply = "Hank" # = gets.chomp
break a if reply == "stop" # do not break
a[i % ngroups] << reply
  #=> a[1 % 3] << "Hank"
  #=> a[1] << "Hank"
  #=> ["Hank"]

Теперь

a #=> => [["Lucy"], ["Hank"], []]

Остальные расчеты аналогичны.

1. Перед запуском следующего мне нужно выполнить enum1.rewind для повторной инициализации перечислителя. См. Перечислитель # перемотка .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...