Find indices of elements that match a given condition

后端 未结 6 1439
小蘑菇
小蘑菇 2020-11-28 09:11

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\', \'.\', \'.\         


        
相关标签:
6条回答
  • 2020-11-28 09:29

    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)
    
    0 讨论(0)
  • 2020-11-28 09:30

    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:

    arr.each_with_index.select { |a,i| a == 'x' }.map &:last
    
    0 讨论(0)
  • 2020-11-28 09:37

    Ruby 1.9:

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

    Code

    0 讨论(0)
  • 2020-11-28 09:39

    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

    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)
    
    0 讨论(0)
  • 2020-11-28 09:45

    I defined Array#index_all which behaves like Array#index but returns all matched indices. This method can take an argument and block.

    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
    
    0 讨论(0)
  • 2020-11-28 09:46

    A slight improvement over your each_with_index.map line

    arr.map.with_index {|a, i| a == 'x' ? i : nil}.compact # => [0, 2, 6]
    
    0 讨论(0)
提交回复
热议问题