How do I find the first two consecutive elements in my array of numbers?

前端 未结 5 771
长发绾君心
长发绾君心 2021-01-25 06:06

Using Ruby 2.4, I have an array of unique, ordered numbers, for example

[1, 7, 8, 12, 14, 15]

How do I find the first two elements whose differ

相关标签:
5条回答
  • 2021-01-25 06:49

    One way to do this:

    a.each_with_index { |e, i| break [ e, a[i.next] ] if a[i.next] == e.next } 
    #=> [7, 8]
    

    Unlike chunk or each_cons this doesn't create an array of arrays. It also breaks as soon as a pair is found.


    Benchmarks

    require 'fruity'
    
    arr = ((1...1000)).to_a.reverse + [1,2]
    
    def first_adjacent_pair(arr)
      idx = arr.each_index.drop(1).find { |i| (arr[i-1]-arr[i]).abs == 1 }
      idx ? arr[idx-1, 2] : nil
    end
    
    def first_adjacent_pair2(arr)
      enum = arr.to_enum
      loop do
        curr = enum.next
        nxt = enum.peek
        return [curr, nxt] if (curr-nxt).abs == 1
      end
      nil
    end
    
    compare do
      iceツ  { ar = arr.dup; ar.each_with_index { |e, i| break [ e, ar[i.next] ] if ar[i.next] == e.next }  }
      cary   { ar = arr.dup; first_adjacent_pair(ar) }
      cary2  { ar = arr.dup; first_adjacent_pair2(ar) }  
      seb    { ar = arr.dup; ar.each_cons(2).find{|a,b| b-a == 1} }
    end
    
    #Running each test 64 times. Test will take about 1 second.
    #cary2 is faster than cary by 3x ± 0.1
    #cary is faster than iceツ by 3x ± 0.1 (results differ: [999, 998] vs [1, 2])
    #iceツ is faster than seb by 30.000000000000004% ± 10.0%
    
    0 讨论(0)
  • 2021-01-25 06:51

    You could use each_cons and find to get the first element from the array of pairs where the second element less the first one is equal to 1:

    p [1, 7, 8, 12, 14, 15].each_cons(2).find { |a, b| b - a == 1 }
    # => [7, 8]
    
    0 讨论(0)
  • 2021-01-25 06:51

    Here's an alternate method provided for educational purposes:

    arr = [1, 7, 8, 12, 14, 15]
    
    arr.each_cons(2).map {|v|v.reduce(:-)}.index(-1)
    
    0 讨论(0)
  • 2021-01-25 06:52

    Here are three more ways.

    #1

    def first_adjacent_pair(arr)
      (arr.size-2).times { |i| return arr[i, 2] if arr[i+1] == arr[i].next }
      nil
    end
    
    first_adjacent_pair [1, 7, 8, 12, 14, 15] #=> [7,8]
    first_adjacent_pair [1, 7, 5, 12, 14, 16] #=> nil
    

    #2

    def first_adjacent_pair(arr)
      enum = arr.to_enum # or arr.each
      loop do
        curr = enum.next
        nxt = enum.peek
        return [curr, nxt] if nxt == curr.next
      end
      nil
    end
    

    enum.peek raises a StopIteration exception when the enumerator enum has generated its last element with the preceding enum.next. The exception is handled by Kernel#loop by breaking out of the loop, after which nil is returned. See also Object#to_enum, Enumerator#next and Enumerator#peek.

    #3

    def first_adjacent_pair(arr)
      a = [nil, arr.first] 
      arr.each do |n|
        a.rotate!
        a[1] = n
        return a if a[1] == a[0] + 1
      end
      nil
    end
    

    See Array#rotate!.

    0 讨论(0)
  • 2021-01-25 06:55

    Simple example

       X = [1, 7, 8, 12, 14, 15]
    
       X.each_with_index do |item, index|
        if index < X.count - 1
         if (X[index+1]-X[index] == 1) 
          puts item
         end
       end
      end
    
    0 讨论(0)
提交回复
热议问题