Есть ли в Ruby функция для увеличения переменной объекта внутри массива в этом примере? - PullRequest
2 голосов
/ 19 октября 2019

Drop1.amount или drop2.amount объекта Drop в этом примере не увеличатся после первого запуска.

class Drop
  attr_accessor :item, :price, :amount
end


drop1 = Drop.new()
drop1.item = "item1"
drop1.price = 2247
drop1.amount = 1

drop2 = Drop.new()
drop2.item = "item2"
drop2.price = 4401
drop2.amount = 60

x = 0
array = []
while x < 10
  rand1 = rand(2)

  if rand1 == 0
    if array.include? drop1.item
      drop1.amount = drop1.amount + 1
    else
      array << drop1.item
      array << drop1.amount
    end

  elsif rand1 == 1
    if array.include? drop2.item
      drop2.amount = drop2.amount + 60
    else
      array << drop2.item
      array << drop2.amount
    end
  end

  x += 1
end

puts array.to_s.gsub('"', '').gsub('[', '').gsub(']', '')
puts ""
puts drop1.amount
puts drop2.amount

Пример ожидаемого вывода:

item2, 240, item1, 6

6
240

Пример фактического результата:

item2, 60, item1, 1

6
240

Я ищу изменения в операторах else в строках 24 и 32. Цель этой программы - создать массив элементов, который будет отображать элемент«один раз и увеличенное количество», когда капля выбирается случайным образом несколько раз.

Ответы [ 2 ]

0 голосов
/ 19 октября 2019

Я не знаю, правильно ли я понимаю логику, но рассмотрим , используя вместо этого хэш массива:

h = {}
10.times do |x|
  rand1 = rand(2)

  if rand1 == 0
    if h.has_key? drop1.item
      drop1.amount += 1
      h[drop1.item] = drop1.amount
    else
      h[drop1.item] = drop1.amount
    end

  elsif rand1 == 1
    if h.has_key? drop2.item
      drop2.amount += 60
      h[drop2.item] = drop2.amount
    else
      h[drop2.item] = drop2.amount
    end
  end

end

Для проверки результата:

p h
p drop1.amount
p drop2.amount


Другой вариант, если он для вас жизнеспособен, позвольте классу выполнить работу , определив его так:
class Drop
  attr_accessor :item, :price, :amount

  def initialize(item:'no_name', price: 0, amount: 0)
    @item = item
    @price = price
    @amount = amount
    @counts = 0
    @increment = amount
  end

  def count!
    @counts += 1
    @amount += @increment if @counts > 1
  end

end

Затем сохраните экземпляры в массиве:

drops = []
drops << Drop.new(item: 'item1', price: 2247, amount: 1)
drops << Drop.new(item: 'item2', price: 4401, amount: 60)

Запустить случайную выборку массива drops:

10.times do |x|
  drops.sample.count!
end

Проверить результат:

drops.each do |drop|
  puts "#{drop.item} - #{drop.amount} - #{drop.price}"
end

Вы также можете определить reset метод, который восстанавливает amount и counts к исходному значению:

def reset
  @amount = @increment
  @count = 0
end
0 голосов
/ 19 октября 2019

array << drop1.amount не создает псевдоним drop1.amount, он делает одноразовую копию числового значения, содержащегося в drop1.amount. При обновлении drop1.amount копия в array не изменяется. Вместо этого поместите ссылку на объект в результирующий массив или обновите значение результирующего массива напрямую (в зависимости от того, хотите ли вы изменить оригинал или нет).

Например, мы можем придерживаться существующего дизайна чем-токак:

# ...
if array.include? drop1.item
  array[array.index(drop1.item)+1] += 1
  drop1.amount += 1 # optionally update the original (less ideal than an alias)
else
  array << drop1.item
  array << drop1.amount
end
# ...
if array.include? drop2.item
  array[array.index(drop2.item)+1] += 60
  drop2.amount += 60   
else
  array << drop2.item
  array << drop2.amount
end
# ...

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

Я бы написалчто-то вроде программы:

Drop = Struct.new(:item, :price, :amount)

drops = [
  Drop.new("item1", 2247, 1),
  Drop.new("item2", 4401, 60)
]
increment_amounts = drops.map {|e| e.amount}
result = [nil] * drops.size

10.times do 
  choice = rand(drops.size)

  if result[choice]
    result[choice].amount += increment_amounts[choice]
  else
    result[choice] = drops[choice]
  end
end

puts result.compact
           .shuffle
           .flat_map {|e| [e.item, e.amount]}
           .to_s
           .gsub(/["\[\]]/, "")
puts "\n" + drops.map {|e| e.amount}.join("\n")

Предложения, которые иллюстрирует вышеприведенная версия:

  • Используйте структуру вместо класса для такого простого типа и задайте его свойства с помощью конструктора, а нечем методы доступа.
  • Используйте массивы вместо thing1, thing2 и т. д. Это значительно упрощает случайный выбор (среди прочего). Обратите внимание, что вышеприведенная версия расширяема, если позже вы решите добавить больше drops. После добавления третьей или 100 капель (вместе с соответствующими суммами приращений) все просто работает.
  • Предпочитайте чистое имя, например result, вместо общего имени, например array.
  • x = 0 ... while x < 10 ... x += 1 более понятен как 10.times.
  • Передавайте регулярное выражение в gsub вместо строки, чтобы избежать объединения нескольких вызовов.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...