【问题标题】:Ruby: How to find difference between 2 arrays, order mattersRuby:如何找到两个数组之间的差异,顺序很重要
【发布时间】:2016-09-12 02:18:30
【问题描述】:

我正在尝试计算两个数组之间的差异,其中顺序很重要。例如:

array_one = ["A", "B", "C"]
array_two = ["B", "C", "A"]

这将产生 3 个差异,因为:

array_one[0] != array_two[0]
array_one[1] != array_two[1]
array_one[2] != array_two[2]

另一个例子:

array_one = ["Z", "X", "Y"]
array_two = ["Z", "W", "Y"]

这将产生 1,因为:

array_one[0] == array_two[0]
array_one[1] != array_two[1]
array_one[2] == array_two[2]

非常感谢任何建议。

【问题讨论】:

    标签: arrays ruby array-difference


    【解决方案1】:

    这个怎么样

    array_one = ["A", "B", "C"]
    array_two = ["A", "C", "A"]
    
    array_one.select.each_with_index { |item, index| 
      array_two[index] != item 
    } => #B and C
    

    【讨论】:

    • 我最近看到了很多使用 .select 的方法。你如何找到这些组合?文档并没有真正显示插入 .select.each_with_index 时会发生什么
    • @KaMok,是的,文档仅显示与特定功能或方法相关的部分。例如,在这种情况下,如果您看到 ruby array select 文档,您将看到选择返回 Enumerator。和Enumerator docs 显示可以与它们一起使用的方法:)。一开始有点难,但随着时间的推移,你会习惯知道如何将一个方法与另一个方法链接起来。阅读文档将帮助您改善这一点..
    【解决方案2】:

    您可以使用zip 合并两个数组,并计算两个值相等的内部数组。

    arr1 = [1,2,3]
    arr2 = [1,5,6]
    
    arr1.zip(arr2)             #=> [[1, 1], [2, 5], [3, 6]]
        .count {|a, b| a == b} #=> 1
    

    另一种方法是遍历两个数组并运行一个计数器

    count = 0
    
    (0...arr1.length).each do |idx|
      count += 1 if arr1[idx] == arr2[idx]
    end
    

    当然,两者都假设两个数组的长度相同。

    (0...arr1.length)0 to arr1.length-1 相同,... 是独占的。

    【讨论】:

    • 根据 ruby​​ 版本,您可以使用 #each_with_index apidock.com/ruby/Enumerator/each_with_index
    • 我想过,在这种情况下我不是each_with_index的粉丝,因为我会在块内有arr1_val == arr2[idx]之类的东西,我这样做是为了统一.
    【解决方案3】:

    仅仅因为我喜欢这样的东西,我对解决方案进行了基准测试,只是想分享一下以防有人感兴趣(我只是将数组切换到更大的数组以获得更有意义的结果)

    require "benchmark/ips"
    
    def method_1(ar_1, ar_2)
      ar = ar_1.zip ar_2
    
      ar.count { |els| els[0] == els[1]  }
    end
    
    def method_2(ar_1, ar_2)
      count = 0
      ar_1.each_with_index { |el, i| count += 1 if el == ar_2[i] }
    end
    
    def method_3(ar_1, ar_2)
      count = 0
    
      (0...ar_1.length).each do |idx|
        count += 1 if ar_1[idx] == ar_2[idx]
      end
    end
    
    def method_4(ar_1, ar_2)
      ar_1.zip(ar_2).inject(0) do |memo, (left, right)|
        if left == right
          memo
        else
          memo + 1
        end
      end
    end
    
    def method_5(ar_1, ar_2)
      ar_1.select.each_with_index do |item, index|
        ar_2[index] != item
      end
    end
    
    Benchmark.ips do |x|
      # ar_1 = ["A", "B", "C"]
      # ar_2 = ["B", "C", "A"]
    
      ar_1 = (0..1_000_000).to_a.shuffle
      ar_2 = (0..1_000_000).to_a.shuffle
    
      x.report("zip and count") do |times|
        i = 0
        while i < times
          method_1 ar_1, ar_2
          i += 1
        end
      end
    
      x.report("each with index") do |times|
        i = 0
        while i < times
          method_2 ar_1, ar_2
          i += 1
        end
      end
    
      x.report("0..length each") do |times|
        i = 0
        while i < times
          method_3 ar_1, ar_2
          i += 1
        end
      end
    
      x.report("zip and inject") do |times|
        i = 0
        while i < times
          method_4 ar_1, ar_2
          i += 1
        end
      end
    
      x.report("select each with index") do |times|
        i = 0
        while i < times
          method_5 ar_1, ar_2
          i += 1
        end
      end
    
      x.compare!
    end
    
    ###################################################
    # 10_000 elements per array                       #
    ###################################################
    #
    # Warming up --------------------------------------
    #        zip and count    54.000  i/100ms
    #      each with index    92.000  i/100ms
    #       0..length each    87.000  i/100ms
    #       zip and inject    41.000  i/100ms
    # select each with index
    #                         82.000  i/100ms
    # Calculating -------------------------------------
    #        zip and count    545.700  (± 2.6%) i/s -      2.754k in   5.050362s
    #      each with index    919.259  (± 3.0%) i/s -      4.600k in   5.008972s
    #       0..length each    919.908  (± 1.4%) i/s -      4.611k in   5.013518s
    #       zip and inject    413.470  (± 1.7%) i/s -      2.091k in   5.058865s
    # select each with index
    #                         828.774  (± 3.5%) i/s -      4.182k in   5.053036s
    #
    # Comparison:
    #       0..length each:      919.9 i/s
    #      each with index:      919.3 i/s - same-ish: difference falls within error
    # select each with index:      828.8 i/s - 1.11x slower
    #        zip and count:      545.7 i/s - 1.69x slower
    #       zip and inject:      413.5 i/s - 2.22x slower
    
    
    ###################################################
    # 1_000_000 elements per array                       #
    ###################################################
    #
    # Warming up --------------------------------------
    #        zip and count     1.000  i/100ms
    #      each with index     1.000  i/100ms
    #       0..length each     1.000  i/100ms
    #       zip and inject     1.000  i/100ms
    # select each with index
    #                          1.000  i/100ms
    # Calculating -------------------------------------
    #        zip and count      5.447  (±18.4%) i/s -     26.000  in   5.088342s
    #      each with index      9.292  (± 0.0%) i/s -     47.000  in   5.058805s
    #       0..length each      9.104  (± 0.0%) i/s -     46.000  in   5.053701s
    #       zip and inject      3.983  (± 0.0%) i/s -     20.000  in   5.042810s
    # select each with index
    #                           7.777  (±12.9%) i/s -     39.000  in   5.053795s
    #
    # Comparison:
    #      each with index:        9.3 i/s
    #       0..length each:        9.1 i/s - 1.02x slower
    # select each with index:        7.8 i/s - 1.19x slower
    #        zip and count:        5.4 i/s - 1.71x slower
    #       zip and inject:        4.0 i/s - 2.33x slower
    

    【讨论】:

      【解决方案4】:

      @davidhu2000 击败了我,但由于这种方法略有不同,因此可能仍然值得一提:

      array_one = ["A", "B", "C"]
      array_two = ["B", "C", "A"]
      
      array_one.zip(array_two).inject(0) { |memo, (left, right)|
        unless left == right
          memo + 1
        else
          memo
        end
      } # => 3
      

      【讨论】:

        【解决方案5】:

        这个怎么样

        array_one = ["A", "B", "C"]
        array_two = ["A", "C", "A"]
        
        array_one.select.each_with_index { |item, index| 
          array_two[index] != item 
        } => #["B", "C"]
        

        【讨论】:

          【解决方案6】:
          array_one = ["A", "B", "C"]
          array_two = ["A", "C", "A"]
          
          enum_two = array_two.to_enum
          array_one.select { |s| s != enum_two.next }
            #=> ["B", "C"] 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-12-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-07-21
            • 1970-01-01
            • 2013-01-02
            相关资源
            最近更新 更多