Исключения на карте в Ruby - PullRequest
1 голос
/ 08 июля 2010

Как создать исключение для карты массива в Ruby. Вот чего я хочу достичь,

a = [1,2,3,4]
b = [5,6,7,8]
a.map.each do |x|
  b.map.each do |y|
    if !(x == 1 && y == 7)
      puts "#{x} and #{y}"
    elsif !(x == 4 && y == 8)
      puts "#{x} and #{y}"
    end
  end
end

1 and 5
1 and 6
1 and 7 # still here
1 and 8
2 and 5
2 and 6
2 and 7
2 and 8
3 and 5
3 and 6
3 and 7
3 and 8
4 and 5
4 and 6
4 and 7
4 and 8 # still here

Однако, это не работает, как мне добавить исключение для этих значений, обрабатываемых картой? Также, если возможно использовать функцию ввода / отклонения / фильтрации с той же целью.

Ответы [ 5 ]

3 голосов
/ 08 июля 2010

Чтобы объяснить, почему 1 и 7 все еще печатают, выполните логику:

  1. if !(x == 1 && y == 7)
    • x == 1 верно и y == 7 верно, поэтому !(true && true) ложно, это пропущено.
  2. elsif !(x == 4 && y == 8)
    • if было пропущено, поэтому elsif оценивается.x == 4 ложно (поскольку x по-прежнему равен 1), а y == 8 ложно (поскольку y по-прежнему равно 7).Таким образом, !(false && false) - это истина, и puts достигается.

Поскольку x никогда не может быть одновременно 1 и 4 одновременно, а yникогда не может быть 7 и 8 одновременно, либо ваше утверждение if, либо ваше выражение elsif всегда будут успешными, и, поскольку обе ветви печатают, значения будут всегда печататься, независимо от того, что x и y.

Как уже говорили другие ответы, вам нужно объединить свои пункты.

2 голосов
/ 08 июля 2010

Это просто проблема непонимания дизъюнктивной семантики в операторе if.

Если вы хотите, чтобы значение НЕ печаталось вообще, оно должно соответствовать ВСЕМ отрицательных условий. Поскольку ваш предикат один и тот же (используется puts), все, что вам нужно сделать, это объединить операторы if с ключевым словом "и".

То есть что-то вроде:

if !(x == 1 && y == 7) and !(x == 4 && y == 8)
1 голос
/ 08 июля 2010

Я думаю, что это то, что вы хотите:

a = [1,2,3,4]
b = [5,6,7,8]
a.map.each do |x|
  b.map.each do |y|
    if !(x == 1 && y == 7) && !(x == 4 && y == 8)
      puts "#{x} and #{y}"
    end
  end
end

(проверено на кодовой панели )

Ваш старый код проверял только то, что !(x == 1 && y == 7) было правдой ИЛИ !(x == 4 && y == 8) было правдой - он не проверял их обоих. Поэтому, когда x равнялся 1, а y равнялся 7, первый puts не выполнялся, а второй выполнялся. Выполните этот код, чтобы лучше отследить его:

a = [1,2,3,4]
b = [5,6,7,8]
a.map.each do |x|
  b.map.each do |y|
    if !(x == 1 && y == 7)
      puts "First #{x} and #{y}"
    elsif !(x == 4 && y == 8)
      puts "SEcond #{x} and #{y}"
    end
  end
end
0 голосов
/ 09 июля 2010

Я думаю, что было бы неплохо разделить отдельные шаги:

  1. вычислить декартово произведение двух массивов: a.product(b)
  2. отфильтровать ненужные пары: reject {|x, y| [[1, 7], [4, 8]].any? {|pair| [x, y] == pair } }
  3. преобразовать в строку: map {|pair| pair.join(' and ') }
  4. напечатать это: puts

Вот что у нас получается:

puts a.product(b).reject {|x, y|
  [[1, 7], [4, 8]].any? {|pair| [x, y] == pair }
}.map {|pair| pair.join(' and ') }
0 голосов
/ 09 июля 2010

Еще один вариант с использованием пропатченного класса Array и метода #reject.

class Array
  def * arr
    outer = []
    self.each do |a|
      arr.each do |b|
        outer << [a,b]
      end
    end
    outer
  end
end


a = [1,2,3,4]
b = [5,6,7,8]

c = (a * b).reject {|pair| pair == [1,7] || pair == [4,8]}

c.each {|pair| puts "#{pair[0]} and #{pair[1]}"}

Не уверен насчет использования оператора '*', потребуется лучшая реализация, если вы хотите сохранить возможность умножать массивы на Fixnum, но мне нравится синтаксис для применения методов к комбинации двух массивов, который довольно распространенное требование.

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