【问题标题】:How do I summarize array of integers as an array of ranges?如何将整数数组总结为范围数组?
【发布时间】:2012-01-27 03:34:06
【问题描述】:

我想接受如下输入:

[1,2,4,5,6,7,9,13]

然后把它变成如下的样子:

[[1,2],[4,7],[9,9],[13,13]]

每个子数组代表一个整数范围。

【问题讨论】:

  • 你是在问是否已经有代码可以做到这一点?您问是因为您正在尝试推出自己的产品并且在实施时遇到困难?
  • 我自己动手。似乎总有一些有趣的方法可以在 Ruby 中实现这种东西。
  • 应该在哪些条件下构建范围?
  • 数组中连续的整数序列应该组成一个“范围”,它实际上只是一个有开始和结束的数组。

标签: ruby arrays algorithm functional-programming range


【解决方案1】:

使用Enumerable#chunk的函数式方法:

ranges = [1, 2, 4, 5, 6, 7, 9, 13]
  .enum_for(:chunk) # .chunk for Ruby >= 2.4
  .with_index { |x, idx| x - idx }
  .map { |_diff, group| [group.first, group.last] }

#=> [[1, 2], [4, 7], [9, 9], [13, 13]]

工作原理:一旦被索引,数组中的连续元素具有相同的x - idx,因此我们使用该值对输入数组进行分块(连续项的分组)。最后,我们只需要获取每个组的第一个和最后一个元素来构建对。

【讨论】:

  • 这看起来真不错。完全忘记了新的块方法。
  • 更进一步,.map{ |min,max| min == max ? min : min .. max } 将导致:[1..2, 4..7, 9, 13]
  • 或者,将[pairs.first[0], pairs.last[0]] 更改为pairs.first[0] .. pairs.last[0] 以获取所有位置的范围:[1..2, 4..7, 9..9, 13..13]
  • 在 Ruby 2.4 中,enum_forno longer be necessary
  • 我还发布了一个更简单的解决方案,chunk_while
【解决方案2】:

这几乎直接来自enumerable#slice_before 方法文档:

ar = [1,2,4,5,6,7,9,13]
prev = ar[0]
ar.slice_before{|e|prev,prev2 = e,prev; prev2.succ != e}.map{|a|a.first..a.last}
#=> [1..2, 4..7, 9..9, 13..13]

这应该适用于字符、日期以及任何带有.succ 方法的东西。

【讨论】:

    【解决方案3】:

    @tokland's very nice one 更简单的解决方案是使用chunk_while

    xs.chunk_while { |a, b| a + 1 == b }.map do |seq|
      [seq.first, seq.last]
    end
    

    注意chunk_while 是在 Ruby 2.3 中引入的

    【讨论】:

      【解决方案4】:

      嗯,好吧,这不是tokland's的杰作,但我认为这可能是一个很好的直接解决方案......

      [1,2,4,5,6,7,9,13].inject([]) do |m, v|
        if m.last.to_a.last == v.pred
          m[-1][-1] = v
        else
          m << [v, v]
        end
        m
      end
      

      【讨论】:

        【解决方案5】:

        另一种方法

        def summarize(x)
          x.inject([]) do |acc, value|
            if acc.last && acc.last[1] + 1 == value
              acc.last[1] = value
              acc
            else
              acc << [value,value]
            end
          end
        end
        

        类似于 Larsenal 的方法,但使用注入来管理无聊的东西。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-10-17
          • 2010-09-12
          • 2017-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多