TypeError: неявное преобразование Symbol в Integer, попытка фильтрации по аргументам - PullRequest
0 голосов
/ 28 апреля 2018

Я пытаюсь отфильтровать массив хэшей на основе параметров хэша, переданных в метод. Я новичок в Ruby с фоном Javascript. Прямо сейчас я пытаюсь выбрать на основе нескольких критериев, в данном случае рейтинг: 4 и цитата: / get /.

class Where
  @boris = {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable. If it doesn't work you can always hit them.", :title => 'Snatch', :rank => 4}
  @charles = {:name => 'Charles De Mar', :quote => 'Go that way, really fast. If something gets in your way, turn.', :title => 'Better Off Dead', :rank => 3}
  @wolf = {:name => 'The Wolf', :quote => 'I think fast, I talk fast and I need you guys to act fast if you wanna get out of this', :title => 'Pulp Fiction', :rank => 4}
  @glen = {:name => 'Glengarry Glen Ross', :quote => "Put. That coffee. Down. Coffee is for closers only.", :title => "Blake", :rank => 5}

  @fixtures = [@boris, @charles, @wolf, @glen]

  def self.where(hash = {})
    arr = []
    hash.each_with_index do |key, index|
      hash_value = hash[hash.keys[index]]
      puts arr;
      case hash_value
      when Integer
        puts 'hitting integer'
        if index === 0
          puts 'hitting 1'
          arr.push(@fixtures.select { |obj| obj[hash.keys[index]] === hash[hash.keys[index]] })
        else
          puts 'hitting 2'
          arr.select { |obj| obj[hash.keys[index]] === hash[hash.keys[index]] }
        end
      when String
        puts 'hitting string'
        if index === 0
          puts 'hitting 3'
          arr.push(@fixtures.select { |obj| obj[hash.keys[index]] === hash[hash.keys[index]] })
        else
          puts 'hitting 4'
          arr.select { |obj| obj[hash.keys[index]] === hash[hash.keys[index]] }
        end
      when Regexp
        puts 'hitting Regexp'
        if index === 0
          puts 'hitting 5'
          arr.push(@fixtures.select { |obj| obj[hash.keys[index]].index(hash[hash.keys[index]]) != nil })
        else
          puts 'hitting 6'
          arr.select { |obj|  obj[hash.keys[index]].index(hash[hash.keys[index]]) != nil }
        end
      end
    end
    return self
  end
end

Where.where(:rank => 4, :quote => /get/)

Я пытаюсь получить [@wolf]

Это то, что я получаю от repl.it

ударяя целое число

ударяя 1

{: name => "Boris The Blade",: quote => "Тяжелый - это хорошо. Тяжелый - это надежно. Если это не сработает, вы всегда можете поразить их.",: Title => "Snatch",: Оценка => 4} {: name => "Волк",: quote => "Я думаю быстро, я говорю быстро, и мне нужно, чтобы вы, ребята, действовали быстро, если хотите выйти из этого",: title => "Криминальное чтиво",: rank => 4}

ударяя регулярное выражение

ударяя 6

1 Ответ

0 голосов
/ 28 апреля 2018

Краткий ответ :

Ошибка вызвана тем, что arr = [], тогда вы вызываете arr.push(<another_array>), что означает, что переменная является массивом массивов .

Позже вы звоните obj[hash.keys[index]], но (из-за вышеизложенного) obj на самом деле Array, а не Hash. Вот почему вы получаете ошибку TypeError: no implicit conversion of Symbol into Integer.

Я мог бы попытаться исправить ваш код с помощью обходного пути (возможно, Array#flatten), но гораздо лучшей идеей было бы реорганизовать объект, чтобы упростить его.

Давайте разгадать этот шаг за шагом:

  1. Почему все эти странные ссылки на hash.keys[index]?

Потому что вы пытаетесь получить 3 переменные, но объявляете только две - поэтому первая - это комбинация двух значений с неправильным именем. Вместо: hash.each_with_index do |key, index| вам нужно: hash.each_with_index do |(key, value), index|. Это упрощает код до:

class Where
  @boris = {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable. If it doesn't work you can always hit them.", :title => 'Snatch', :rank => 4}
  @charles = {:name => 'Charles De Mar', :quote => 'Go that way, really fast. If something gets in your way, turn.', :title => 'Better Off Dead', :rank => 3}
  @wolf = {:name => 'The Wolf', :quote => 'I think fast, I talk fast and I need you guys to act fast if you wanna get out of this', :title => 'Pulp Fiction', :rank => 4}
  @glen = {:name => 'Glengarry Glen Ross', :quote => "Put. That coffee. Down. Coffee is for closers only.", :title => "Blake", :rank => 5}

  @fixtures = [@boris, @charles, @wolf, @glen]

  def self.where(hash = {})
    arr = []
    hash.each_with_index do |(key, value), index|
      puts arr;
      case value
      when Integer
        puts 'hitting integer'
        if index === 0
          puts 'hitting 1'
          arr.push(@fixtures.select { |obj| obj[key] === value })
        else
          puts 'hitting 2'
          arr.select { |obj| obj[key] === value }
        end
      when String
        puts 'hitting string'
        if index === 0
          puts 'hitting 3'
          arr.push(@fixtures.select { |obj| obj[key] === value })
        else
          puts 'hitting 4'
          arr.select { |obj| obj[key] === value }
        end
      when Regexp
        puts 'hitting Regexp'
        if index === 0
          puts 'hitting 5'
          arr.push(@fixtures.select { |obj| obj[key].index(value) != nil })
        else
          puts 'hitting 6'
          arr.select { |obj|  obj[key].index(value) != nil }
        end
      end
    end
    return self
  end
end

puts Where.where(:rank => 4, :quote => /get/)

(Обратите внимание, что я еще не исправил вашу ошибку!)

  1. Почему существует переменная arr, а логика окружает if index === 0?

Исправление требует небольшого изменения мышления - ваш текущий дизайн может работать только для проверки до двух условий в хэше where, так как вы сохраняете результаты первой проверки во временном массиве. Это не нужно; вместо этого вы можете написать что-то вроде:

class Where
  @boris = {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable. If it doesn't work you can always hit them.", :title => 'Snatch', :rank => 4}
  @charles = {:name => 'Charles De Mar', :quote => 'Go that way, really fast. If something gets in your way, turn.', :title => 'Better Off Dead', :rank => 3}
  @wolf = {:name => 'The Wolf', :quote => 'I think fast, I talk fast and I need you guys to act fast if you wanna get out of this', :title => 'Pulp Fiction', :rank => 4}
  @glen = {:name => 'Glengarry Glen Ross', :quote => "Put. That coffee. Down. Coffee is for closers only.", :title => "Blake", :rank => 5}

  @fixtures = [@boris, @charles, @wolf, @glen]

  def self.where(hash = {})
    @fixtures.select do |fixture|
      hash.all? do |key, value|
        case value
        when Integer
          puts 'hitting integer'
          fixture[key] === value
        when String
          puts 'hitting string'
          fixture[key] === value
        when Regexp
          puts 'hitting Regexp'
          fixture[key] === value
        end
      end
    end
  end
end

puts Where.where(:rank => 4, :quote => /get/)

(Вау, это сократило лот! - и переменная index теперь даже не нужна. Это исправляет вашу первоначальную ошибку, но код по-прежнему не совсем работает ...)

  1. Сравнение String === Regexp всегда будет неудачным.

См. документацию - вам действительно нужно использовать Regexp === String здесь, а не наоборот. Изменение этого, наконец, дает нам рабочий код:

class Where
  @boris = {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable. If it doesn't work you can always hit them.", :title => 'Snatch', :rank => 4}
  @charles = {:name => 'Charles De Mar', :quote => 'Go that way, really fast. If something gets in your way, turn.', :title => 'Better Off Dead', :rank => 3}
  @wolf = {:name => 'The Wolf', :quote => 'I think fast, I talk fast and I need you guys to act fast if you wanna get out of this', :title => 'Pulp Fiction', :rank => 4}
  @glen = {:name => 'Glengarry Glen Ross', :quote => "Put. That coffee. Down. Coffee is for closers only.", :title => "Blake", :rank => 5}

  @fixtures = [@boris, @charles, @wolf, @glen]

  def self.where(hash = {})
    @fixtures.select do |fixture|
      hash.all? do |key, value|
        case value
        when Integer
          puts 'hitting integer'
          value === fixture[key]
        when String
          puts 'hitting string'
          value === fixture[key]
        when Regexp
          puts 'hitting Regexp'
          value === fixture[key]
        end
      end
    end
  end
end

puts Where.where(:rank => 4, :quote => /get/)
  1. Это все еще очень повторяется! ...

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

class Where
  @boris = {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable. If it doesn't work you can always hit them.", :title => 'Snatch', :rank => 4}
  @charles = {:name => 'Charles De Mar', :quote => 'Go that way, really fast. If something gets in your way, turn.', :title => 'Better Off Dead', :rank => 3}
  @wolf = {:name => 'The Wolf', :quote => 'I think fast, I talk fast and I need you guys to act fast if you wanna get out of this', :title => 'Pulp Fiction', :rank => 4}
  @glen = {:name => 'Glengarry Glen Ross', :quote => "Put. That coffee. Down. Coffee is for closers only.", :title => "Blake", :rank => 5}

  @fixtures = [@boris, @charles, @wolf, @glen]

  def self.where(hash = {})
    @fixtures.select do |fixture|
      hash.all? do |key, value|
        puts "Checking #{key} => #{value.inspect}"
        value === fixture[key]
      end
    end
  end
end

puts Where.where(:rank => 4, :quote => /get/)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...