Ruby: find the index of the next match in the array or find with offset

I want to find the following matches after matches Array#find_index { |item| block }for the first time. How can I find the index of the second match, third match, etc.?

In other words, I want the equivalent argument posfor Regexp#match(str, pos)for Array#find_index. Then I can save the index of the current position to continue the search.

I cannot use Enumerable#find_allit because I can change the array between calls (in this case, I will also adjust the index of the current position to reflect the changes). I do not want to copy part of the array, as this would increase the computational complexity of my algorithm. I want to do this without copying the array:

new_pos = pos + array[pos..-1].find_index do |elem|
    elem.matches_condition?
end

Below are various questions. They request only the first match in the array, plus one:

The following question is closer, but it still doesn’t help me, because I need to process the first match before moving on to the next one (and this method also contradicts the modification):

+4
source share
4 answers

The simplest way to do this is simple:

new_pos = pos
while new_pos < array.size and not array[new_pos].matches_condition?
    new_pos += 1
end
new_pos = nil if new_pos == array.size

In fact, I think this is probably better than my other answer because it is harder to make a mistake and there is no chance that future shading problems will be introduced from the surrounding code. However, he is still clumsy.

And if the condition is more complicated, then you need to do something like this:

new_pos = pos
# this check is only necessary if pos may be == array.size
if new_pos < array.size
    prepare_for_condition
end
while new_pos < array.size and not array[new_pos].matches_condition?
    new_pos += 1
    if new_pos < array.size
        prepare_for_condition
    end
end
new_pos = nil if new_pos == array.size

, , begin ... end while ( new_pos):

new_pos = pos - 1
begin
    new_pos += 1
    if new_pos < array.size
        prepare_for_condition
    end
end while new_pos < array.size and not array[new_pos].matches_condition?
new_pos = nil if new_pos == array.size

. , , prepare_for_condition - , . ; , , - . - . ; , , .

+2

. Array, , . , .

Enumerator, Enumerator next, to_a ..

ary = [1,2,3,4,5,6]

class Array
  def find_index_r(&block)
    Enumerator.new do |yielder| 
      self.each_with_index{|i, j| yielder.yield j if block.call(i)}
    end
  end
end

e = ary.find_index_r { |r| r % 2 == 0 }

p e.to_a  #=> [1, 3, 5]
p e.next  
#=> 1
p e.next  
#=> 3
ary[2]=10 
p ary
#=> [1, 2, 10, 4, 5, 6]
p e.next  
#=> 5
e.rewind
p e.next  
#=> 1
p e.next  
#=> 2

. Array .

+2

, :

new_pos = pos + (pos...array.size).find_index do |index|
    elem = array[index]
    elem.matches_condition?
end

. , pos. , , elem -. , .

, Array#find_index Array#index . , , Regexp#match(str,pos) 1.9, .

+1

,

arr = [9,1,4,1,9,36,25]
findees = [1,6,3,6,3,7]
proc = ->(n) { n**2 }

n findees m of arr which proc[n] == m. , n=3, proc[3] #==> 9, arr 0. n=3 findees arr 4.

:

arr = [9,1,4,1,9,36,25]
findees = [1,6,3,6,3,7]
proc = ->(n) { n**2 }

h = arr.each_with_index.with_object(Hash.new { |h,k| h[k] = [] }) { |(n,i),h| h[n] << i }
  #=> {9=>[0, 4], 1=>[1, 3], 4=>[2], 36=>[5], 25=>[6]}
findees.each_with_object([]) { |n,a| v=h[proc[n]]; a << v.shift if v }
  #=> [1, 5, 0, nil, 4, nil]

Array :

class Array
  def find_indices(*args)
    h = each_with_index.with_object(Hash.new {|h,k| h[k] = []}) { |(n,i),h| h[n] << i }
    args.each_with_object([]) { |n,a| v=h[yield n]; a << v.shift if v }
  end
end

arr.find_indices(*findees) { |n| n**2 }
  #=> [1, 5, 0, nil, 4, nil]

arr = [3,1,2,1,3,6,5]
findees = [1,6,3,6,3,7]
arr.find_indices(*findees, &:itself)
  #=> [1, 5, 0, nil, 4, nil]
0

Source: https://habr.com/ru/post/1617977/


All Articles