【问题标题】:Replace consecutive integers in an array with ranges用范围替换数组中的连续整数
【发布时间】:2021-12-23 21:48:05
【问题描述】:

我想将连续整数组合到一个排序数组中,并使用jq 将它们替换为范围。

示例 1

输入:[1,2,3,4,6,98,99,101]
所需输出:"1-4,6,98-99,101"

示例 2

输入:[1,3,5]
所需输出:"1,3,5"

示例 3

输入:[1,2,3,4,5]
所需输出:"1-5"

我找到了一个使用foreach 的解决方案,但它对我来说似乎不是很优雅和紧凑。

这个任务有更简单的解决方案吗?

[foreach (.[], 99999) as $current
  ({};
   if length == 0 then
     {first: $current}
   elif (has("last") | not) and .first + 1 != $current then
     {first: $current, extract: "\(.first)"}
   elif has("last") and .last + 1 != $current then
     {first: $current, extract: "\(.first)-\(.last)"}
   else
     {first, last: $current}
   end;
   .extract // empty
  )]
| join(",")

【问题讨论】:

    标签: jq


    【解决方案1】:

    我会分两步完成。


    首先,分组。

    reduce .[] as $_ (
       [];
       if $_ - 1 == .[-1][1] then
          .[-1][1] = $_
       else
          . + [ [ $_, $_ ] ]
       end
    )
    

    这一步产生[[1,1],[2,4],[6,6],[98,99],[101,101]]


    然后,构建字符串。

    map(
       if .[0] == .[1] then
          "\( .[0] )"
       else
          "\( .[0] )-\( .[1] )"
       end
    ) |
    join(",")
    

    Demojqplay

    它并没有更短,但我认为它更简单、更干净。

    此外,分离关注点不仅有助于简化和清晰。您可以选择将代码隐藏在两个小函数中。而且您可以更轻松地自定义输出,例如生成98,99 而不是98-99[98,99]。您甚至可以决定在根本不需要生成字符串的地方重用代码。

    但最重要的是,这个解决方案消除了99999 的魔力!

    【讨论】:

    • 请注意,如果输入以1 开头,$_ == .[-1][1] + 1 会失败,这就是我使用$_ - 1 == .[-1][1] 的原因。如果减法令人反感,也可以使用.[-1] and $_ == .[-1][1] + 1
    • 非常感谢您提供的替代解决方案。很好,逻辑不再需要幻数。
    【解决方案2】:

    这是另一个解决方案:

    reduce .[1:][] as $n ([.[:1]];
      if $n == .[-1][-1] + 1 then .[-1][1] = $n else . + [[$n]] end
    ) | map(join("-")) | join(",")
    

    喂食时

    [1,2,3,4,6,98,99,101]
    [1,3,5]
    [1,2,3,4,5]
    [4]
    []
    

    输出

    "1-4,6,98-99,101"
    "1,3,5"
    "1-5"
    "4"
    ""
    

    Demo

    【讨论】:

    • 非常紧凑的解决方案。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 2013-05-18
    • 1970-01-01
    • 2011-07-21
    相关资源
    最近更新 更多