Как использовать массив Ruby в этом случае? - PullRequest
0 голосов
/ 05 июля 2018

Вот массив ruby:

array = ['x', 3, 0, 4, 4, 7]

Я хочу отобразить через array, взять каждое целое число в массиве (кроме 0) минус 2 и вернуть новый массив.

Когда есть буквы, они не будут изменены.

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

['x', 1, 0, 2, 2, 5]

Это то, что у меня есть, но я получил сообщение об ошибке "неопределенное целое число метода?", Может кто-нибудь сказать мне, в чем проблема?

    def minusNumber(array)
     array.map do |e|
      if e.integer? && e !== 0
      e - 2
      end
     end
    end

Ответы [ 6 ]

0 голосов
/ 05 июля 2018

Я думаю, что это разборчиво и элегантно:

array.map { |v| v.is_a?(Integer) && v == 0 ? v : v -2 }
0 голосов
/ 05 июля 2018

Вы можете сделать это без проверки типа.

использование kind_of? это запах кода, который говорит, что ваш код процедурный, а не объектно-ориентированный ... https://www.sandimetz.com/blog/2009/06/12/ruby-case-statements-and-kind-of

def someMethod(arr)
  arr.map do |item|
    next item unless item.to_i.nonzero?
    item - 2
  end
end

someMethod(["x", 3, 0, 4, 4, 7])

> ["x", 1, 0, 2, 2, 5]
0 голосов
/ 05 июля 2018

Другие ответы здесь будут хорошо работать с вашим текущим вводом. Что-то вроде:

def minusNumber(array)
  array.map do |e|
    if e.is_a?(Integer) && e != 0
      e - 2
    else
      e
    end
  end
end

Но вот более гибкое решение. Это может быть слишком сложным для вас, где вы сейчас находитесь, но все обучение - это хорошее обучение: -)

Ruby - это язык, который допускает полиморфизм в своих переменных. Используя пример ввода для вашего метода, вы можете видеть, что переменная e может содержать объект String или объект Integer. Но на самом деле он может содержать любой тип объекта, и Ruby не будет заботиться об одном бите, если только он не обнаружит ошибку при использовании переменной.

Итак. В вашем примере вам нужно сохранить Integer s в выводе. Но что, если в будущем вам понадобится передать массив, содержащий несколько Score объектов, и они вам понадобятся и в вашем выводе? Это совершенно новый класс, который вы еще даже не написали, но знаете, что позже вы это сделаете. Есть способ, которым вы можете переписать свой метод, который будет предвидеть этот будущий класс, и все другие классы типа Integer, которые вы можете когда-нибудь написать.

Вместо использования #is_a? для проверки типа объекта используйте #respond_to?, чтобы проверить, какие методы он реализует.

Любой класс, который может использоваться как целое число , должен реализовывать метод #to_int . Integer конечно, и ваш класс Score будет, но String нет. И ни один другой класс не может рассматриваться как целое число. Так что это будет работать для всех типов значений, правильно разделяя те, которые отвечают на #to_int, и те, которые не отвечают.

def minusNumber(array)
  array.map do |e|
    if e.respond_to?(:to_int) && e != 0
      e - 2
    else
      e
    end
  end
end

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

0 голосов
/ 05 июля 2018

Коротко и сладко.

array.map { |v| v.is_a?(Integer) && !v.zero? ? v - 2 : v }

Это исключает все ненужные операторы case, многократные итерации и преобразования. Просто берет каждый элемент, если он является целым числом и больше 0, то вычитает 2, иначе ничего не делает.

0 голосов
/ 05 июля 2018

Вот еще один вариант:

array = ['x', 3, 0, 4, 4, 7]

transformed = array.map do |e|
  case e
  when 0, String
    e
  when Integer
    e - 2
  else
    fail 'unexpected input'
  end
end

transformed # => ["x", 1, 0, 2, 2, 5]

Жаль, что вам нужно сохранить элементы, из которых вы не вычли 2. Я действительно хотел сделать что-то подобное

array.grep(Integer).reject(&:zero?).map{|i| i - 2 } # => [1, 2, 2, 5]

Не удалось найти способ (сохраняющий необработанные элементы).

0 голосов
/ 05 июля 2018

Как упомянуто в комментарии выше, вы должны использовать метод is_a? для проверки типа данных элемента. Код ниже должен работать как положено:

 def minusNumber(array)
   array.map do |e|
     if e.is_a?(String) || e == 0
       e
     else
       e - 2
     end
   end
 end

Вместо оператора if вы также можете сделать:

(e.is_a?(String) || e == 0 ) ? e : e-2

Обратите внимание, что исходный объект не изменяется, если вы не используете map!

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