Как проверить, содержит ли значение массива одно или несколько значений? - PullRequest
22 голосов
/ 04 февраля 2011

Я смотрю, есть ли в массиве одно или несколько значений.Например, что-то вроде этого:

[1,2,3,4,5,6].include?([4,1])  # => true
[4,1,6,2].include?([4,1])  # => true
[3,4,7].include?([4,1])  # => false

Конечно, «включать?»Метод может проверять только одно значение.Есть ли способ проверки нескольких значений?

Ответы [ 12 ]

57 голосов
/ 04 февраля 2011
>> [1,2,3,4,5,6] & [4,1]
=> [1, 4]
>> [1,2,3,4,5,6] & [7,9]
=> []
>>
26 голосов
/ 04 февраля 2011

Это заданная операция.Set находится в стандартной библиотеке.

require 'set'

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

b.subset? a
#=> true
16 голосов
/ 04 февраля 2011

РЕДАКТИРОВАТЬ: Я одобряю Марк Томас ' альтернативное решение, которое использует ядро ​​Set класс .

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

Существует множество веских причин для использования массивов (поддержание порядка, позволяющеедля дубликатов), для которых все еще достаточно нижеследующего, но если ни один из них не задействован, sjsc может выиграть от использования Set вместо Array, и в этом смысле решение Марка семантически лучше.


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

class Array
  def subset?(a)
    (self - a).length == 0
  end
end

Я уверен, что есть вычислительно более эффективные способы сделать это,но это должно сделать то, что вы ищете.

Выполнение пересечения массива работает и в основном равносильно тому же.

class Array
  def subset?(a)
    (self & a).length == length
  end
end

Оптимизацияна этом уровне не слишком поможет, но вы не хотите начинать сравнивать массивы несколько раз:

class Array
  # don't do this
  def subset?(a)
    (self & a) == a
  end
end
6 голосов
/ 04 февраля 2011

Быстрое и грязное расширение подхода @ Schwartzie:

larger_array = [1,2,3,4,5,6]
smaller_array = [4,1]
smaller_array.all? {|smaller_array_item| larger_array.include?(smaller_array_item)}
4 голосов
/ 15 декабря 2014

Основываясь на предложении Куруми и Спайла, вот мой тест:

([1,2,3,4,5,6] & [4,1]). Любой?# => true

Тем не менее, .any?превратит все объекты в истинные

([1,2,3,4,5,6] и [6,7]). any?# => true

Так что я думаю, что здесь может быть рабочий:

([1,2,3,4,5,6] & [6,7]). Length == [6,7] .length # => false

(*

3 голосов
/ 04 февраля 2011

Что не так с [1,2,3,4,5,6].include?(4) and [1,2,3,4,5,6].include?(1)?

2 голосов
/ 31 января 2015

Мне нравится ответ Куруми, но просто добавлю еще один:

>> set1 = [1,2,3,4,5,6]
[
    [0] 1,
    [1] 2,
    [2] 3,
    [3] 4,
    [4] 5,
    [5] 6
]
>> set2 = [4,1]
[
    [0] 4,
    [1] 1
]
>> set1.any?{ |num| set2.include?(num) }
true
>> set2 = [8,9]
[
    [0] 8,
    [1] 9
]
>> set1.any?{ |num| set2.include?(num) }
false
2 голосов
/ 08 марта 2012

Я пришел к выводу, что метод Вычитание , как правило, хорош, но фактический Набор объектов сверкает быстро, поскольку они явно оптимизированы для этого типа вычислений.

Используя этот скрипт: https://gist.github.com/1996001

Я получил следующие результаты тестов (на Ruby 1.9.2p290):

SUBTRACTION
- subset
  0.180000   0.000000   0.180000 (  0.189767)
- partial subset
  0.170000   0.000000   0.170000 (  0.178700)
- non subset
  0.180000   0.000000   0.180000 (  0.177606)

INTERSECTION
- subset
  0.190000   0.000000   0.190000 (  0.194149)
- partial subset
  0.190000   0.000000   0.190000 (  0.191253)
- non subset
  0.190000   0.000000   0.190000 (  0.195798)

SET
- subset
  0.050000   0.000000   0.050000 (  0.048634)
- partial subset
  0.040000   0.000000   0.040000 (  0.045927)
- non subset
  0.050000   0.010000   0.060000 (  0.052925)

Что я считаю довольно поразительным, особенно если вы проверите источник:

# File 'lib/set.rb', line 204

def subset?(set)
  set.is_a?(Set) or raise ArgumentError, "value must be a set"
  return false if set.size < size
  all? { |o| set.include?(o) }
end

через: http://rubydoc.info/stdlib/set/1.9.2/Set#subset%3F-instance_method

1 голос
/ 04 февраля 2011

@ kurumi все правильно, но я подумал, что добавлю, что иногда использую это маленькое расширение, когда хочу только подмножество массива (хотя обычно это хеш-ключи):

class Hash
  # Usage { :a => 1, :b => 2, :c => 3}.except(:a) -> { :b => 2, :c => 3}
  def except(*keys)
    self.reject { |k,v|
      keys.include? k
    }
  end

  # Usage { :a => 1, :b => 2, :c => 3}.only(:a) -> {:a => 1}
  def only(*keys)
    self.dup.reject { |k,v|
      !keys.include? k
    }
  end
end

class Array
  def except(*values)
    self.reject { |v|
      values.include? v
    }
  end

  def only(*values)
    self.reject { |v|
      !values.include? v
    }
  end
end
0 голосов
/ 15 февраля 2019

Для проверки значений массива, содержащих один или несколько элементов, вы можете преобразовать массив в "set", а затем использовать "subset?" метод как показано ниже.

    require "set"
    a = [1,2,3,4,5,6]
    b = [3,6]
    b.to_set.subset?a.to_set //true
    b= [3,7]
    b.to_set.subset?a.to_set //false
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...