相似名称和数字的数组到范围组中

Array of similar names and numbers into ranged groups

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

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

如何将具有相似名称的值分组到如下所示的范围内?

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

请注意,数字并不总是连续的(检查 "tablet" 值)

假设数字是连续的:

["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 和 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"]

这是一种方法。

代码

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(在 v.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"]