我有一个值“狗”和一个数组[“猫”、“狗”、“鸟”]。
如何在不循环的情况下检查数组中是否存在它?是否有一种简单的方法来检查该值是否存在?
我有一个值“狗”和一个数组[“猫”、“狗”、“鸟”]。
如何在不循环的情况下检查数组中是否存在它?是否有一种简单的方法来检查该值是否存在?
当前回答
我总是觉得运行一些基准测试来查看各种方法的相对速度很有趣。
在开始、中间或结束处查找数组元素将影响任何线性搜索,但几乎不会影响对集合的搜索。
将一个数组转换为一个集合会导致处理时间的减少,所以从一个数组创建一次集合,或者从一开始就创建一个集合。
以下是基准代码:
# frozen_string_literal: true
require 'fruity'
require 'set'
ARRAY = (1..20_000).to_a
SET = ARRAY.to_set
DIVIDER = '-' * 20
def array_include?(elem)
ARRAY.include?(elem)
end
def array_member?(elem)
ARRAY.member?(elem)
end
def array_index(elem)
ARRAY.index(elem) >= 0
end
def array_find_index(elem)
ARRAY.find_index(elem) >= 0
end
def array_index_each(elem)
ARRAY.index { |each| each == elem } >= 0
end
def array_find_index_each(elem)
ARRAY.find_index { |each| each == elem } >= 0
end
def array_any_each(elem)
ARRAY.any? { |each| each == elem }
end
def array_find_each(elem)
ARRAY.find { |each| each == elem } != nil
end
def array_detect_each(elem)
ARRAY.detect { |each| each == elem } != nil
end
def set_include?(elem)
SET.include?(elem)
end
def set_member?(elem)
SET.member?(elem)
end
puts format('Ruby v.%s', RUBY_VERSION)
{
'First' => ARRAY.first,
'Middle' => (ARRAY.size / 2).to_i,
'Last' => ARRAY.last
}.each do |k, element|
puts DIVIDER, k, DIVIDER
compare do
_array_include? { array_include?(element) }
_array_member? { array_member?(element) }
_array_index { array_index(element) }
_array_find_index { array_find_index(element) }
_array_index_each { array_index_each(element) }
_array_find_index_each { array_find_index_each(element) }
_array_any_each { array_any_each(element) }
_array_find_each { array_find_each(element) }
_array_detect_each { array_detect_each(element) }
end
end
puts '', DIVIDER, 'Sets vs. Array.include?', DIVIDER
{
'First' => ARRAY.first,
'Middle' => (ARRAY.size / 2).to_i,
'Last' => ARRAY.last
}.each do |k, element|
puts DIVIDER, k, DIVIDER
compare do
_array_include? { array_include?(element) }
_set_include? { set_include?(element) }
_set_member? { set_member?(element) }
end
end
在我的Mac OS笔记本电脑上运行时,会导致:
Ruby v.2.7.0
--------------------
First
--------------------
Running each test 65536 times. Test will take about 5 seconds.
_array_include? is similar to _array_index
_array_index is similar to _array_find_index
_array_find_index is faster than _array_any_each by 2x ± 1.0
_array_any_each is similar to _array_index_each
_array_index_each is similar to _array_find_index_each
_array_find_index_each is faster than _array_member? by 4x ± 1.0
_array_member? is faster than _array_detect_each by 2x ± 1.0
_array_detect_each is similar to _array_find_each
--------------------
Middle
--------------------
Running each test 32 times. Test will take about 2 seconds.
_array_include? is similar to _array_find_index
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 2x ± 0.1
_array_member? is faster than _array_index_each by 2x ± 0.1
_array_index_each is similar to _array_find_index_each
_array_find_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0%
_array_detect_each is similar to _array_find_each
--------------------
Last
--------------------
Running each test 16 times. Test will take about 2 seconds.
_array_include? is faster than _array_find_index by 10.000000000000009% ± 10.0%
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 3x ± 0.1
_array_member? is faster than _array_find_index_each by 2x ± 0.1
_array_find_index_each is similar to _array_index_each
_array_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0%
_array_detect_each is similar to _array_find_each
--------------------
Sets vs. Array.include?
--------------------
--------------------
First
--------------------
Running each test 65536 times. Test will take about 1 second.
_array_include? is similar to _set_include?
_set_include? is similar to _set_member?
--------------------
Middle
--------------------
Running each test 65536 times. Test will take about 2 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 1400x ± 1000.0
--------------------
Last
--------------------
Running each test 65536 times. Test will take about 4 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 3000x ± 1000.0
基本上,如果我要搜索包含,结果告诉我对所有内容都使用Set,除非我能保证第一个元素是我想要的,这不太可能。在哈希表中插入元素时会有一些开销,但搜索速度要快得多,我认为这不应该是一个考虑因素。同样,如果您需要搜索它,请不要使用数组,而是使用集合。(或哈希。)
Array越小,Array方法运行得越快,但它们仍然无法跟上,尽管在小数组中,差异可能很小。
“First”、“Middle”和“Last”反映了所搜索元素在ARRAY中使用First、size/2和Last。搜索ARRAY和SET变量时将使用该元素。
对与>0进行比较的方法进行了轻微更改,因为索引类型测试的测试应为>=0。
有关Fruity及其方法的更多信息,请参见其README。
其他回答
检查是否存在
使用include?
例子:
arr = [1, 2, 3]
arr.include?(1) -> true
arr.include?(4) -> false
支票不存在
使用排除?
例子:
arr = %w(vietnam china japan)
arr.exclude?('usa') -> true
arr.exclude?('china') -> false
Try
['Cat', 'Dog', 'Bird'].include?('Dog')
使用Enumerable#include:
a = %w/Cat Dog Bird/
a.include? 'Dog'
或者,如果完成了大量测试,1您可以摆脱循环(甚至包括?has),并通过以下方式从O(n)变为O(1):
h = Hash[[a, a].transpose]
h['Dog']
1.我希望这是显而易见的,但为了避免反对意见:是的,对于几个查找,Hash[]和转置操作占据了配置文件的主导地位,并且每个操作本身都是O(n)。
我总是觉得运行一些基准测试来查看各种方法的相对速度很有趣。
在开始、中间或结束处查找数组元素将影响任何线性搜索,但几乎不会影响对集合的搜索。
将一个数组转换为一个集合会导致处理时间的减少,所以从一个数组创建一次集合,或者从一开始就创建一个集合。
以下是基准代码:
# frozen_string_literal: true
require 'fruity'
require 'set'
ARRAY = (1..20_000).to_a
SET = ARRAY.to_set
DIVIDER = '-' * 20
def array_include?(elem)
ARRAY.include?(elem)
end
def array_member?(elem)
ARRAY.member?(elem)
end
def array_index(elem)
ARRAY.index(elem) >= 0
end
def array_find_index(elem)
ARRAY.find_index(elem) >= 0
end
def array_index_each(elem)
ARRAY.index { |each| each == elem } >= 0
end
def array_find_index_each(elem)
ARRAY.find_index { |each| each == elem } >= 0
end
def array_any_each(elem)
ARRAY.any? { |each| each == elem }
end
def array_find_each(elem)
ARRAY.find { |each| each == elem } != nil
end
def array_detect_each(elem)
ARRAY.detect { |each| each == elem } != nil
end
def set_include?(elem)
SET.include?(elem)
end
def set_member?(elem)
SET.member?(elem)
end
puts format('Ruby v.%s', RUBY_VERSION)
{
'First' => ARRAY.first,
'Middle' => (ARRAY.size / 2).to_i,
'Last' => ARRAY.last
}.each do |k, element|
puts DIVIDER, k, DIVIDER
compare do
_array_include? { array_include?(element) }
_array_member? { array_member?(element) }
_array_index { array_index(element) }
_array_find_index { array_find_index(element) }
_array_index_each { array_index_each(element) }
_array_find_index_each { array_find_index_each(element) }
_array_any_each { array_any_each(element) }
_array_find_each { array_find_each(element) }
_array_detect_each { array_detect_each(element) }
end
end
puts '', DIVIDER, 'Sets vs. Array.include?', DIVIDER
{
'First' => ARRAY.first,
'Middle' => (ARRAY.size / 2).to_i,
'Last' => ARRAY.last
}.each do |k, element|
puts DIVIDER, k, DIVIDER
compare do
_array_include? { array_include?(element) }
_set_include? { set_include?(element) }
_set_member? { set_member?(element) }
end
end
在我的Mac OS笔记本电脑上运行时,会导致:
Ruby v.2.7.0
--------------------
First
--------------------
Running each test 65536 times. Test will take about 5 seconds.
_array_include? is similar to _array_index
_array_index is similar to _array_find_index
_array_find_index is faster than _array_any_each by 2x ± 1.0
_array_any_each is similar to _array_index_each
_array_index_each is similar to _array_find_index_each
_array_find_index_each is faster than _array_member? by 4x ± 1.0
_array_member? is faster than _array_detect_each by 2x ± 1.0
_array_detect_each is similar to _array_find_each
--------------------
Middle
--------------------
Running each test 32 times. Test will take about 2 seconds.
_array_include? is similar to _array_find_index
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 2x ± 0.1
_array_member? is faster than _array_index_each by 2x ± 0.1
_array_index_each is similar to _array_find_index_each
_array_find_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0%
_array_detect_each is similar to _array_find_each
--------------------
Last
--------------------
Running each test 16 times. Test will take about 2 seconds.
_array_include? is faster than _array_find_index by 10.000000000000009% ± 10.0%
_array_find_index is similar to _array_index
_array_index is faster than _array_member? by 3x ± 0.1
_array_member? is faster than _array_find_index_each by 2x ± 0.1
_array_find_index_each is similar to _array_index_each
_array_index_each is similar to _array_any_each
_array_any_each is faster than _array_detect_each by 30.000000000000004% ± 10.0%
_array_detect_each is similar to _array_find_each
--------------------
Sets vs. Array.include?
--------------------
--------------------
First
--------------------
Running each test 65536 times. Test will take about 1 second.
_array_include? is similar to _set_include?
_set_include? is similar to _set_member?
--------------------
Middle
--------------------
Running each test 65536 times. Test will take about 2 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 1400x ± 1000.0
--------------------
Last
--------------------
Running each test 65536 times. Test will take about 4 minutes.
_set_member? is similar to _set_include?
_set_include? is faster than _array_include? by 3000x ± 1000.0
基本上,如果我要搜索包含,结果告诉我对所有内容都使用Set,除非我能保证第一个元素是我想要的,这不太可能。在哈希表中插入元素时会有一些开销,但搜索速度要快得多,我认为这不应该是一个考虑因素。同样,如果您需要搜索它,请不要使用数组,而是使用集合。(或哈希。)
Array越小,Array方法运行得越快,但它们仍然无法跟上,尽管在小数组中,差异可能很小。
“First”、“Middle”和“Last”反映了所搜索元素在ARRAY中使用First、size/2和Last。搜索ARRAY和SET变量时将使用该元素。
对与>0进行比较的方法进行了轻微更改,因为索引类型测试的测试应为>=0。
有关Fruity及其方法的更多信息,请参见其README。
有趣的事实,
可以使用*检查case表达式中的数组成员资格。
case element
when *array
...
else
...
end
注意when子句中的小*,它检查数组中的成员身份。
splat运算符的所有常见魔术行为都适用,所以例如,如果数组实际上不是一个数组,而是一个元素,那么它将匹配该元素。