ruby 查找与给定条件匹配的元素的索引
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13659696/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Find indices of elements that match a given condition
提问by Misha Moroshko
Given an array, how can I find all indices of elements those match a given condition?
给定一个数组,如何找到与给定条件匹配的元素的所有索引?
For example, if I have:
例如,如果我有:
arr = ['x', 'o', 'x', '.', '.', 'o', 'x']
To find all indices where the item is x, I could do:
要查找项目所在的所有索引x,我可以执行以下操作:
arr.each_with_index.map { |a, i| a == 'x' ? i : nil }.compact # => [0, 2, 6]
or
或者
(0..arr.size-1).select { |i| arr[i] == 'x' } # => [0, 2, 6]
Is there a nicer way to achieve this?
有没有更好的方法来实现这一目标?
回答by steenslag
回答by AGS
Another way:
其它的办法:
arr.size.times.select {|i| arr[i] == 'x'} # => [0, 2, 6]
EDIT:
编辑:
Not sure if this is even needed, but here they are.
不确定是否需要这样做,但它们就在这里。
Benchmarks:
基准:
arr = 10000000.times.map{rand(1000)};
Benchmark.measure{arr.each_with_index.map { |a, i| a == 50 ? i : nil }.compact}
2.090000 0.120000 2.210000 ( 2.205431)
Benchmark.measure{(0..arr.size-1).select { |i| arr[i] == 50 }}
1.600000 0.000000 1.600000 ( 1.604543)
Benchmark.measure{arr.map.with_index {|a, i| a == 50 ? i : nil}.compact}
1.810000 0.020000 1.830000 ( 1.829151)
Benchmark.measure{arr.each_index.select{|i| arr[i] == 50}}
1.590000 0.000000 1.590000 ( 1.584074)
Benchmark.measure{arr.size.times.select {|i| arr[i] == 50}}
1.570000 0.000000 1.570000 ( 1.574474)
回答by Sergio Tulentsev
A slight improvement over your each_with_index.mapline
对您的each_with_index.map线路略有改进
arr.map.with_index {|a, i| a == 'x' ? i : nil}.compact # => [0, 2, 6]
回答by peter
This methods is a bit longer but double as fast
这种方法有点长,但速度加倍
class Array
def find_each_index find
found, index, q = -1, -1, []
while found
found = self[index+1..-1].index(find)
if found
index = index + found + 1
q << index
end
end
q
end
end
arr = ['x', 'o', 'x', '.', '.', 'o', 'x']
p arr.find_each_index 'x'
# [0, 2, 6]
Here the benchmark of AGS campared with this solution
这里是 AGS 的基准测试与此解决方案的对比
arr = 10000000.times.map{rand(1000)};
puts Benchmark.measure{arr.each_with_index.map { |a, i| a == 50 ? i : nil }.compact}
puts Benchmark.measure{(0..arr.size-1).select { |i| arr[i] == 50 }}
puts Benchmark.measure{arr.map.with_index {|a, i| a == 50 ? i : nil}.compact}
puts Benchmark.measure{arr.each_index.select{|i| arr[i] == 50}}
puts Benchmark.measure{arr.size.times.select {|i| arr[i] == 50}}
puts Benchmark.measure{arr.find_each_index 50}
# 1.263000 0.031000 1.294000 ( 1.267073)
# 0.843000 0.000000 0.843000 ( 0.846048)
# 0.936000 0.015000 0.951000 ( 0.962055)
# 0.842000 0.000000 0.842000 ( 0.839048)
# 0.843000 0.000000 0.843000 ( 0.843048)
# 0.405000 0.000000 0.405000 ( 0.410024)
回答by Mark Reed
Not sure if you consider this an improvement or not, but using (map+ compact) as a filter feels very clunky to me. I would use select, since that's what it's for, and then just grab the part of the result I care about:
不确定您是否认为这是一种改进,但是使用 ( map+ compact) 作为过滤器对我来说感觉很笨拙。我会使用select,因为这就是它的用途,然后只获取我关心的结果部分:
arr.each_with_index.select { |a,i| a == 'x' }.map &:last
回答by Junichi Ito
I defined Array#index_allwhich behaves like Array#indexbut returns all matched indices. This method can take an argument and block.
我定义了Array#index_all它的行为,Array#index但返回所有匹配的索引。这个方法可以接受一个参数并阻塞。
class Array
def index_all(obj = nil)
if obj || block_given?
proc = obj ? ->(i) { self[i] == obj } : ->(i) { yield self[i] }
self.each_index.select(&proc)
else
self.each
end
end
end
require 'test/unit'
class TestArray < Test::Unit::TestCase
def test_index_all
arr = ['x', 'o', 'x', '.', '.', 'o', 'x']
result = arr.index_all('x')
assert_equal [0, 2, 6], result
arr = [100, 200, 100, 300, 100, 400]
result = arr.index_all {|n| n <= 200 }
assert_equal [0, 1, 2, 4], result
end
end

