类似名称和数字的数组到范围组

时间:2015-05-18 23:14:54

标签: arrays ruby range

我有一个如下所示的数组:

["mac1", "mac2", "mac3", "win1", "win2", "win3", "tablet1", "tablet2", "tablet3", "tablet5"] 

如何将具有相似名称的值分组到这样的范围内?

["mac1-3", "win1-3", "tablet1-3", "tablet5"]

请注意,这些数字并不总是连续的(请查看"数位板"值)

3 个答案:

答案 0 :(得分:1)

假设这些数字是连续的:

["mac1", "mac2", "mac3", "win1", "win2", "win3"] 
.group_by{|e| e[/\D+/]}
.map{|k, v| k + v.map{|s| s[/\d+/].to_i}.minmax.join("-")}
# => ["mac1-3", "win1-3"]

答案 1 :(得分:1)

这是一种方法。

<强>代码

def group_em(arr)
  arr.map { |w| [w[/[a-z]+/i], w[/\d+/].to_i] }
     .sort
     .slice_when { |(e1,n1),(e2,n2)| (e1 != e2) || n2 > n1+1 }
     .map do |arr|
        s = "#{arr.first.first}#{arr.first.last}"
        (arr.size>1) ? (s << "-#{arr.last.last}") : s
      end
end

示例

arr = ["tablet2", "win2", "tablet3", "win1", "win3", "mac1",
       "tablet99", "mac3", "mac2", "tablet1"] 
group_em(arr)
  #=> ["mac1-3", "tablet1-3", "tablet99", "win1-3"]     

<强>解释

a = arr.map { |w| [w[/[a-z]+/i], w[/\d+/].to_i] }.sort
  #=> [["mac", 1], ["mac", 2], ["mac", 3], ["tablet", 1], ["tablet", 2],
  #    ["tablet", 3], ["tablet", 99], ["win", 1], ["win", 2], ["win", 3]]

使用Enumerable#slice_when(在第2.2节中介绍)切片:

e = a.slice_when { |(e1,n1),(e2,n2)| (e1 != e2) || n2 > n1+1 }
  #=> #<Enumerator: #<Enumerator::Generator:0x007ffb1c8547a0>:each> 

我们可以通过将它转换为数组来查看此枚举器的元素:

e.to_a
  #=> [[["mac", 1], ["mac", 2], ["mac", 3]],
  #    [["tablet", 1], ["tablet", 2], ["tablet", 3]],
  #    [["tablet", 99]],
  #    [["win", 1], ["win", 2], ["win", 3]]] 

最后:

e.map do |arr|
  s = "#{arr.first.first}#{arr.first.last}"
  (arr.size>1) ? (s << "-#{arr.last.last}") : s
end
  #=> ["mac1-3", "tablet1-3", "tablet99", "win1-3"] 

答案 2 :(得分:0)

假设数字之间没有中断(即如果我们有值1和3则存在2)

input = ["mac1", "mac2", "mac3", "win1", "win2", "win3"]
h = input.each_with_object({}) do |i, h|
  m = i.match(/(.*?)(\d+)/)
  fst = m[1]
  snd = m[2].to_i

  h[fst] = [] if h[fst].nil?
  h[fst] << snd
end

output = h.each_with_object([]) do |(k, v), a|
  a << "#{k}#{v.min}-#{v.max}"
end

puts output  # outputs ["mac1-3", "win1-3"]