将连续整数序列放入组中

时间:2014-08-14 19:05:45

标签: ruby algorithm grouping

我有一组Line个对象。每行都有一个row_number属性,它是一个整数:

Line.row_number = 1,
Line.row_number = 2,
Line.row_number = 3,
Line.row_number = 5,
Line.row_number = 6,
Line.row_number = 20,
Line.row_number = 24,
Line.row_number = 25,
Line.row_number = 0

我想创建一个哈希,其键是整数,值是连续row_numbers的所有行。我希望哈希看起来像这样:

0 => 
Line.row_number = 0,
Line.row_number = 1,
Line.row_number = 2,
Line.row_number = 3,
Line.row_number = 5,
Line.row_number = 6,

1 => 
Line.row_number = 20

2 =>
Line.row_number = 24,
Line.row_number = 25,

有人可以让我知道我可以用哪种算法来实现这个目标吗?

3 个答案:

答案 0 :(得分:2)

您可以对数组进行排序,然后迭代它。如果当前元素不等于前一个元素+1,则启动新组。

答案 1 :(得分:1)

您在问题中提供的示例不是有效的Ruby代码,因此很难理解您要执行的操作。我假设你的目标的本质是转换一个数组:

[1,2,24,3,5,6,20,25,0]

到一个看起来像这样的哈希:

{ 0=>[0,1,2,3], 1=>[5,6], 2=>[20], 3=>[24,25] }

<强>代码

def hashify(arr)    
  a = arr.sort
  curr_val = a.first
  a.slice_before do |i|
    last_val = curr_val
    curr_val = i
    last_val + 1 < curr_val  
  end.with_index.with_object({}) { |(arr,j),h| h[j]=arr }
end

示例

hashify [1,2,24,3,5,6,20,25,0]
  #=> {0=>[0, 1, 2, 3], 1=>[5, 6], 2=>[20], 3=>[24, 25]}

<强>解释

arr = [1,2,24,3,5,6,20,25,0]
a = arr.sort
  #=> [0, 1, 2, 3, 5, 6, 20, 24, 25]
curr_val = a.first
  #=> 0
enum0 = a.slice_before do |i|
      last_val = curr_val
      curr_val = i
      last_val + 1 < curr_val  
    end
  #=> #<Enumerator: #<Enumerator::Generator:0x0000010109aea0>:each>
enum0.to_a
  #=> [[0, 1, 2, 3], [5, 6], [20], [24, 25]]
enum1 = enum0.with_index
  #=> #<Enumerator: #<Enumerator: \
  #   #<Enumerator::Generator:0x0000010109aea0>:each>:with_index>
enum1.to_a
  #=> [[[0, 1, 2, 3], 0], [[5, 6], 1], [[20], 2], [[24, 25], 3]]
enum2 = enum1.with_object({})
  #=> #<Enumerator: #<Enumerator: #<Enumerator: \
  #   #<Enumerator::Generator:0x0000010109aea0>:each>:with_index>:with_object({})>
enum2.to_a
  #=> [[[[0, 1, 2, 3], 0], {}], [[[5, 6], 1], {}], [[[20], 2], {}], [[[24, 25], 3], {}]]
enum2.each { |(a,j),h| h[j]=a }
  #=> {0=>[0, 1, 2, 3], 1=>[5, 6], 2=>[20], 3=>[24, 25]}

enum0enum1enum2都是枚举者。您可以将后两者视为“复合”枚举器。 enum0.to_a显示值enum0将传递到其块(如果有的话)。 enum1.to_aenum2.to_a相同(后者确实有一个块)。

考虑最后一步。 enum2传递到块中的each的第一个值是[[0,1,2,3],0],{}]。这些分配给块变量如下:

a => [0, 1, 2, 3]
j => 0
h => {}

h[0] = [0, 1, 2, 3]    

已执行,因此哈希现在是:

h #=> {0=>[0, 1, 2, 3]}

each传递给块的第二个值将以下值分配给块变量:

a = [5, 6]
j = 1
h = {0=>[0, 1, 2, 3]}

h[1] = [5, 6]
执行

,结果是:

h #=> {0=>[0, 1, 2, 3], 1=>[5, 6]}

each将剩余的两个值传递给块,并执行simliar计算,然后枚举器返回h

答案 2 :(得分:-1)

使用array.sort_by(&:row_number).group_by{ |e| e.row_number.div(10) }

> Line = Struct.new(:row_number)
> t = 0.upto(20).each.map{ |i| Line.new(i) }.shuffle
> t.sort_by(&:row_number).group_by{ |e| e.row_number.div(10) }
=> {0=>[#<struct Line row_number=0>, #<struct Line row_number=1>, #<struct Line row_number=2>, #<struct Line row_number=3>, #<struct Line row_number=4>, #<struct Line row_number=5>, #<struct Line row_number=6>, #<struct Line row_number=7>, #<struct Line row_number=8>, #<struct Line row_number=9>],
    1=>[#<struct Line row_number=10>, #<struct Line row_number=11>, #<struct Line row_number=12>, #<struct Line row_number=13>, #<struct Line row_number=14>, #<struct Line row_number=15>, #<struct Line row_number=16>, #<struct Line row_number=17>, #<struct Line row_number=18>, #<struct Line row_number=19>],
    2=>[#<struct Line row_number=20>]}