Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays Ruby:查找数组中下一个匹配项的索引,或使用偏移量查找_Arrays_Ruby - Fatal编程技术网

Arrays Ruby:查找数组中下一个匹配项的索引,或使用偏移量查找

Arrays Ruby:查找数组中下一个匹配项的索引,或使用偏移量查找,arrays,ruby,Arrays,Ruby,我想在Array#find_index{| item | block}首次匹配之后找到更多匹配项。如何搜索第二个匹配项、第三个匹配项等的索引 换句话说,对于数组#find_index,我需要与pos参数等价的Regexp#match(str,pos)。然后我可以维护当前位置索引以继续搜索 我不能使用Enumerable#find_all,因为我可能会在调用之间修改数组(在这种情况下,我还将调整当前位置索引以反映修改)。我不想复制数组的一部分,因为那样会增加算法的效率。我希望在不复制阵列的情况下执

我想在
Array#find_index{| item | block}
首次匹配之后找到更多匹配项。如何搜索第二个匹配项、第三个匹配项等的索引

换句话说,对于
数组#find_index
,我需要与
pos
参数等价的
Regexp#match(str,pos)
。然后我可以维护当前位置索引以继续搜索

我不能使用
Enumerable#find_all
,因为我可能会在调用之间修改数组(在这种情况下,我还将调整当前位置索引以反映修改)。我不想复制数组的一部分,因为那样会增加算法的效率。我希望在不复制阵列的情况下执行此操作:

new_pos = pos + array[pos..-1].find_index do |elem|
    elem.matches_condition?
end
以下是不同的问题。他们只询问数组中的第一个匹配项,外加一个:

下面的问题更接近,但仍然对我没有帮助,因为我需要在继续下一个匹配之前处理第一个匹配(这种方式也与修改冲突):


    • 当然,一种方法是:

      new_pos = pos + (pos...array.size).find_index do |index|
          elem = array[index]
          elem.matches_condition?
      end
      
      然而,这是笨拙的,很容易出错。例如,您可能忘记添加
      pos
      。此外,您必须确保
      elem
      没有隐藏某些内容。这两种情况都会导致难以追踪的bug


      我发现很难相信
      Array#find#u index
      Array#index
      的索引参数仍然没有进入语言。然而,我注意到,直到1.9版才出现了
      Regexp#match(str,pos)
      ,这同样令人惊讶。

      一种更简单的方法就是:

      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
      

      这可能看起来很可怕。然而,假设
      prepare\u for\u condition
      一直在以小的方式进行调整。这些调整最终将得到重构;然而,到那时,重构代码的输出也将以一些不属于旧的重构代码的小方式得到调整,但似乎还不能证明它们自己的重构是合理的——等等。有时,有人会忘记改变这两个地方。这似乎是病态的;然而,正如我们所知,在编程中,病理病例有一个习惯,就是发生得太频繁。

      这里有一种方法可以做到这一点。我们可以在
      Array
      类中定义一个新方法,该方法允许我们查找与给定条件匹配的索引。条件可以指定为返回布尔值的块

      新方法返回一个
      枚举器
      ,这样我们就可以从许多
      枚举器
      方法中获益,例如
      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
      类中添加了一个新方法。解决方案可以很容易地适应工作,而无需使用猴子补丁

      arr = [9,1,4,1,9,36,25]
      findees = [1,6,3,6,3,7]
      proc = ->(n) { n**2 }
      
      对于
      findees
      中的每个元素
      n
      ,我们需要
      arr
      的第一个不匹配元素
      m
      的索引,用于
      哪个过程[n]==m
      。例如,如果
      n=3
      ,则
      proc[3]#==>9
      ,因此
      arr
      中的第一个匹配索引将是
      0
      。对于
      findees
      中的下一个
      n=3
      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#find_索引。这是简洁的表格

      def find_next_index(a,prior=nil)
          (((prior||-1)+1)...a.length).find{|i| yield a[i]}
      end
      
      下面是一个简单的测试用例

      test_arr = %w(aa ab ac ad)
      puts find_next_index(test_arr){|v| v.include?('a')}
      puts find_next_index(test_arr,1){|v| v.include?('a')}
      puts find_next_index(test_arr,3){|v| v.include?('a')}
      
      # evaluates to:
      #     0
      #     2
      #     nil
      

      当然,只需稍加重写,您就可以将其添加到Array类中

      为什么要发布一个“笨拙且容易出错”的答案?因为在某些情况下,这将是您唯一(或最好)的选择,除非使用monkey patching。我想说服Ruby团队,他们应该在标准库方法“find#u index”(可能还有其他方法)中添加一个position(或offset)参数。我喜欢你的方法,但你做得太多了。
      枚举器中的所有内容。新的
      块可以替换为
      每个带索引的{item,idx | yielder.yield(idx)if block.call(item)}
      。看一看:谢谢@Jordan-我已经根据你的建议更新了我的答案。但是如果我在调用e.next之间修改数组,这是否仍然保证有效?@martinjs不确定你在说什么样的修改。如果更新已遍历的元素,则在执行
      枚举器#rewind
      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]
      
      def find_next_index(a,prior=nil)
          (((prior||-1)+1)...a.length).find{|i| yield a[i]}
      end
      
      test_arr = %w(aa ab ac ad)
      puts find_next_index(test_arr){|v| v.include?('a')}
      puts find_next_index(test_arr,1){|v| v.include?('a')}
      puts find_next_index(test_arr,3){|v| v.include?('a')}
      
      # evaluates to:
      #     0
      #     2
      #     nil