Ruby 查找与给定条件匹配的元素的索引

Ruby 查找与给定条件匹配的元素的索引,ruby,arrays,Ruby,Arrays,给定一个数组,如何找到与给定条件匹配的元素的所有索引 例如,如果我有: arr = ['x', 'o', 'x', '.', '.', 'o', 'x'] 要查找项目为x的所有索引,我可以执行以下操作: arr.each_with_index.map { |a, i| a == 'x' ? i : nil }.compact # => [0, 2, 6] 或 有没有更好的方法来实现这一点?另一种方法: arr.size.times.select {|i| arr[i] == 'x'

给定一个数组,如何找到与给定条件匹配的元素的所有索引

例如,如果我有:

arr = ['x', 'o', 'x', '.', '.', 'o', 'x']
要查找项目为
x
的所有索引,我可以执行以下操作:

arr.each_with_index.map { |a, i| a == 'x' ? i : nil }.compact   # => [0, 2, 6]

有没有更好的方法来实现这一点?

另一种方法:

arr.size.times.select {|i| arr[i] == 'x'} # => [0, 2, 6]
编辑:

不确定是否需要,但它们在这里

基准:

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)

使用_index.map行比您的
每个_稍有改进

arr.map.with_index {|a, i| a == 'x' ? i : nil}.compact # => [0, 2, 6]
Ruby 1.9:

arr = ['x', 'o', 'x', '.', '.', 'o', 'x']
p arr.each_index.select{|i| arr[i] == 'x'} # =>[0, 2, 6]

此方法稍长,但速度加倍

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]

不确定你是否认为这是一个改进,但是使用(<代码>地图<代码> +>代码>紧凑< <代码> >作为一个过滤器对我来说感觉很笨拙。我会使用

选择
,因为这就是它的用途,然后抓住我关心的结果部分:

arr.each_with_index.select { |a,i| a == 'x' }.map &:last
我定义了
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
类数组
def index_all(obj=nil)
如果给出obj | |块| U?
proc=obj?->(i) {self[i]==obj}:->(i){yield self[i]}
self.each_index.select(&proc)
其他的
各自
结束
结束
结束
需要“测试/单元”
类TestArray结果=arr.index\u all{| n | n您是否在寻找逻辑或语法,可以帮助您了解逻辑但不了解语法:)不太熟悉ruby…您可以使用
regexp
我猜逻辑和语法都可以:)不确定是否将regex视为不必要的字符串。这是我认为Python的列表理解确实读起来更好的少数情况之一:
[i代表i,如果a=='x'],则a在枚举(arr)中]
。a
可枚举#查找(elem)会让我感到不舒服
不在ruby stdlib中。不知何故,这会提出合理的功能请求。请注意,这仅在使用带参数的索引时有效,而不适用于块。对于块,接受的解决方案仍然是唯一的方法。感谢这一点。我只为(:each_with_index)找到了
arr.enum_。收集{item,index | item='x'?index:nil}。如果{i | i.nil?}
在此之前。@6ftDan
如果{i | i.nil?}
=
compact
。出于好奇,p在这个例子中做什么?@user5783745
p
以“开发人员友好”的方式将表达式的结果打印到屏幕上。在这种情况下:
[0,2,6]
@user5783745
my_var=p arr.each_index.选择{i|arr[i]=='x'}
可以使用或不使用
p
upvoted来实现最合理的实现。其他任何东西都更复杂。我认为公认的答案更简单;
arr.size.times==arr.each_index
。只需一个方法调用,而不是两个。但是根据这里添加的基准测试,显然会稍微慢一点?
arr.each_with_index.select { |a,i| a == 'x' }.map &:last
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