How to collapse consecutive numbers into ranges?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
4
down vote

favorite
1












Given a sorted input file (or command output) that contains unique numbers, one per line, I would like to collapse all runs of consecutive numbers into ranges such that



n
n+1
...
n+m


becomes



n,n+m



input sample:



2
3
9
10
11
12
24
28
29
33


expected output:



2,3
9,12
24
28,29
33









share|improve this question























  • Very nice question, but would benefit from some clarifications for newbies. Please !
    – TNT
    7 hours ago










  • @TNT - let me know which part is unclear
    – don_crissti
    6 hours ago










  • thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
    – TNT
    5 hours ago











  • @TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
    – don_crissti
    4 hours ago















up vote
4
down vote

favorite
1












Given a sorted input file (or command output) that contains unique numbers, one per line, I would like to collapse all runs of consecutive numbers into ranges such that



n
n+1
...
n+m


becomes



n,n+m



input sample:



2
3
9
10
11
12
24
28
29
33


expected output:



2,3
9,12
24
28,29
33









share|improve this question























  • Very nice question, but would benefit from some clarifications for newbies. Please !
    – TNT
    7 hours ago










  • @TNT - let me know which part is unclear
    – don_crissti
    6 hours ago










  • thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
    – TNT
    5 hours ago











  • @TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
    – don_crissti
    4 hours ago













up vote
4
down vote

favorite
1









up vote
4
down vote

favorite
1






1





Given a sorted input file (or command output) that contains unique numbers, one per line, I would like to collapse all runs of consecutive numbers into ranges such that



n
n+1
...
n+m


becomes



n,n+m



input sample:



2
3
9
10
11
12
24
28
29
33


expected output:



2,3
9,12
24
28,29
33









share|improve this question















Given a sorted input file (or command output) that contains unique numbers, one per line, I would like to collapse all runs of consecutive numbers into ranges such that



n
n+1
...
n+m


becomes



n,n+m



input sample:



2
3
9
10
11
12
24
28
29
33


expected output:



2,3
9,12
24
28,29
33






text-processing numeric-data






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 7 hours ago









Jeff Schaller

32.6k849110




32.6k849110










asked 7 hours ago









don_crissti

47.2k15125155




47.2k15125155











  • Very nice question, but would benefit from some clarifications for newbies. Please !
    – TNT
    7 hours ago










  • @TNT - let me know which part is unclear
    – don_crissti
    6 hours ago










  • thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
    – TNT
    5 hours ago











  • @TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
    – don_crissti
    4 hours ago

















  • Very nice question, but would benefit from some clarifications for newbies. Please !
    – TNT
    7 hours ago










  • @TNT - let me know which part is unclear
    – don_crissti
    6 hours ago










  • thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
    – TNT
    5 hours ago











  • @TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
    – don_crissti
    4 hours ago
















Very nice question, but would benefit from some clarifications for newbies. Please !
– TNT
7 hours ago




Very nice question, but would benefit from some clarifications for newbies. Please !
– TNT
7 hours ago












@TNT - let me know which part is unclear
– don_crissti
6 hours ago




@TNT - let me know which part is unclear
– don_crissti
6 hours ago












thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
– TNT
5 hours ago





thank you. just not clear to me what it means n then n+1. given first number is 2 then I assume first range 2,3 then second range should be 9,10 then 10-11 how you calculated the "expected output" ranges. Would be appreciated if you explain.
– TNT
5 hours ago













@TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
– don_crissti
4 hours ago





@TNT - consecutive ="following each other continuously" (I'm 100% sure consecutive has the same meaning in all languages) so when I say collapse all consecutive numbers I mean all consecutive numbers like n, n+1, n+2, n+3 and so on (à la n++) up to n+m should be combined into a single range: n,n+m. So combine as many numbers as possible as long as they are consecutive.
– don_crissti
4 hours ago











4 Answers
4






active

oldest

votes

















up vote
4
down vote













awk '
function output() print start (prev == start ? "" : ","prev)
NR == 1 start = prev = $1; next
$1 > prev+1 output(); start = $1
prev = $1
END output()
'





share|improve this answer



























    up vote
    2
    down vote













    Perl approach!



    #!/bin/perl
    print ranges(2,3,9,10,11,12,24,28,29,33), "n";

    sub ranges
    my @vals = @_;
    my $first = $vals[0];
    my $last;
    my @list;
    for my $i (0 .. (scalar(@vals)-2))
    if (($vals[$i+1] - $vals[$i]) != 1)
    $last = $vals[$i];
    push @list, ($first == $last) ? $first : "$first,$last";
    $first = $vals[$i+1];


    $last = $vals[-1];
    push @list, ($first == $last) ? $first : "$first,$last";
    return join ("n", @list);






    share|improve this answer


















    • 2




      24,24 and 33,33 is not quite what was requested...
      – RudiC
      6 hours ago










    • As your awk approach is quite similar to glenn jackman's and mine, refer to those.
      – RudiC
      4 hours ago

















    up vote
    1
    down vote













    How about



    awk '
    $0 > LAST+1 if (NR > 1) print (PR != LAST)?"," LAST:""
    printf "%s", $0
    PR = $0

    LAST = $0

    END print (PR != LAST)?"," LAST:""

    ' file
    2,3
    9,12
    24
    28,29
    33





    share|improve this answer






















    • I'd stick to lower case variable names, but that's just style. I came up with the same logic.
      – glenn jackman
      7 hours ago










    • Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
      – glenn jackman
      7 hours ago











    • I might recheck. I'm not too happy with the clumsy logics anyhow.
      – RudiC
      7 hours ago


















    up vote
    1
    down vote













    awk, with a different (more C-like) approach:



    awk ' do for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1); print s==e ? s : s","e while(r>0) ' file





    share|improve this answer






















      Your Answer







      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "106"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f470073%2fhow-to-collapse-consecutive-numbers-into-ranges%23new-answer', 'question_page');

      );

      Post as a guest






























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      4
      down vote













      awk '
      function output() print start (prev == start ? "" : ","prev)
      NR == 1 start = prev = $1; next
      $1 > prev+1 output(); start = $1
      prev = $1
      END output()
      '





      share|improve this answer
























        up vote
        4
        down vote













        awk '
        function output() print start (prev == start ? "" : ","prev)
        NR == 1 start = prev = $1; next
        $1 > prev+1 output(); start = $1
        prev = $1
        END output()
        '





        share|improve this answer






















          up vote
          4
          down vote










          up vote
          4
          down vote









          awk '
          function output() print start (prev == start ? "" : ","prev)
          NR == 1 start = prev = $1; next
          $1 > prev+1 output(); start = $1
          prev = $1
          END output()
          '





          share|improve this answer












          awk '
          function output() print start (prev == start ? "" : ","prev)
          NR == 1 start = prev = $1; next
          $1 > prev+1 output(); start = $1
          prev = $1
          END output()
          '






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 7 hours ago









          glenn jackman

          47.6k265104




          47.6k265104






















              up vote
              2
              down vote













              Perl approach!



              #!/bin/perl
              print ranges(2,3,9,10,11,12,24,28,29,33), "n";

              sub ranges
              my @vals = @_;
              my $first = $vals[0];
              my $last;
              my @list;
              for my $i (0 .. (scalar(@vals)-2))
              if (($vals[$i+1] - $vals[$i]) != 1)
              $last = $vals[$i];
              push @list, ($first == $last) ? $first : "$first,$last";
              $first = $vals[$i+1];


              $last = $vals[-1];
              push @list, ($first == $last) ? $first : "$first,$last";
              return join ("n", @list);






              share|improve this answer


















              • 2




                24,24 and 33,33 is not quite what was requested...
                – RudiC
                6 hours ago










              • As your awk approach is quite similar to glenn jackman's and mine, refer to those.
                – RudiC
                4 hours ago














              up vote
              2
              down vote













              Perl approach!



              #!/bin/perl
              print ranges(2,3,9,10,11,12,24,28,29,33), "n";

              sub ranges
              my @vals = @_;
              my $first = $vals[0];
              my $last;
              my @list;
              for my $i (0 .. (scalar(@vals)-2))
              if (($vals[$i+1] - $vals[$i]) != 1)
              $last = $vals[$i];
              push @list, ($first == $last) ? $first : "$first,$last";
              $first = $vals[$i+1];


              $last = $vals[-1];
              push @list, ($first == $last) ? $first : "$first,$last";
              return join ("n", @list);






              share|improve this answer


















              • 2




                24,24 and 33,33 is not quite what was requested...
                – RudiC
                6 hours ago










              • As your awk approach is quite similar to glenn jackman's and mine, refer to those.
                – RudiC
                4 hours ago












              up vote
              2
              down vote










              up vote
              2
              down vote









              Perl approach!



              #!/bin/perl
              print ranges(2,3,9,10,11,12,24,28,29,33), "n";

              sub ranges
              my @vals = @_;
              my $first = $vals[0];
              my $last;
              my @list;
              for my $i (0 .. (scalar(@vals)-2))
              if (($vals[$i+1] - $vals[$i]) != 1)
              $last = $vals[$i];
              push @list, ($first == $last) ? $first : "$first,$last";
              $first = $vals[$i+1];


              $last = $vals[-1];
              push @list, ($first == $last) ? $first : "$first,$last";
              return join ("n", @list);






              share|improve this answer














              Perl approach!



              #!/bin/perl
              print ranges(2,3,9,10,11,12,24,28,29,33), "n";

              sub ranges
              my @vals = @_;
              my $first = $vals[0];
              my $last;
              my @list;
              for my $i (0 .. (scalar(@vals)-2))
              if (($vals[$i+1] - $vals[$i]) != 1)
              $last = $vals[$i];
              push @list, ($first == $last) ? $first : "$first,$last";
              $first = $vals[$i+1];


              $last = $vals[-1];
              push @list, ($first == $last) ? $first : "$first,$last";
              return join ("n", @list);







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 4 hours ago

























              answered 7 hours ago









              Goro

              3,05441951




              3,05441951







              • 2




                24,24 and 33,33 is not quite what was requested...
                – RudiC
                6 hours ago










              • As your awk approach is quite similar to glenn jackman's and mine, refer to those.
                – RudiC
                4 hours ago












              • 2




                24,24 and 33,33 is not quite what was requested...
                – RudiC
                6 hours ago










              • As your awk approach is quite similar to glenn jackman's and mine, refer to those.
                – RudiC
                4 hours ago







              2




              2




              24,24 and 33,33 is not quite what was requested...
              – RudiC
              6 hours ago




              24,24 and 33,33 is not quite what was requested...
              – RudiC
              6 hours ago












              As your awk approach is quite similar to glenn jackman's and mine, refer to those.
              – RudiC
              4 hours ago




              As your awk approach is quite similar to glenn jackman's and mine, refer to those.
              – RudiC
              4 hours ago










              up vote
              1
              down vote













              How about



              awk '
              $0 > LAST+1 if (NR > 1) print (PR != LAST)?"," LAST:""
              printf "%s", $0
              PR = $0

              LAST = $0

              END print (PR != LAST)?"," LAST:""

              ' file
              2,3
              9,12
              24
              28,29
              33





              share|improve this answer






















              • I'd stick to lower case variable names, but that's just style. I came up with the same logic.
                – glenn jackman
                7 hours ago










              • Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
                – glenn jackman
                7 hours ago











              • I might recheck. I'm not too happy with the clumsy logics anyhow.
                – RudiC
                7 hours ago















              up vote
              1
              down vote













              How about



              awk '
              $0 > LAST+1 if (NR > 1) print (PR != LAST)?"," LAST:""
              printf "%s", $0
              PR = $0

              LAST = $0

              END print (PR != LAST)?"," LAST:""

              ' file
              2,3
              9,12
              24
              28,29
              33





              share|improve this answer






















              • I'd stick to lower case variable names, but that's just style. I came up with the same logic.
                – glenn jackman
                7 hours ago










              • Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
                – glenn jackman
                7 hours ago











              • I might recheck. I'm not too happy with the clumsy logics anyhow.
                – RudiC
                7 hours ago













              up vote
              1
              down vote










              up vote
              1
              down vote









              How about



              awk '
              $0 > LAST+1 if (NR > 1) print (PR != LAST)?"," LAST:""
              printf "%s", $0
              PR = $0

              LAST = $0

              END print (PR != LAST)?"," LAST:""

              ' file
              2,3
              9,12
              24
              28,29
              33





              share|improve this answer














              How about



              awk '
              $0 > LAST+1 if (NR > 1) print (PR != LAST)?"," LAST:""
              printf "%s", $0
              PR = $0

              LAST = $0

              END print (PR != LAST)?"," LAST:""

              ' file
              2,3
              9,12
              24
              28,29
              33






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 7 hours ago

























              answered 7 hours ago









              RudiC

              1,2167




              1,2167











              • I'd stick to lower case variable names, but that's just style. I came up with the same logic.
                – glenn jackman
                7 hours ago










              • Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
                – glenn jackman
                7 hours ago











              • I might recheck. I'm not too happy with the clumsy logics anyhow.
                – RudiC
                7 hours ago

















              • I'd stick to lower case variable names, but that's just style. I came up with the same logic.
                – glenn jackman
                7 hours ago










              • Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
                – glenn jackman
                7 hours ago











              • I might recheck. I'm not too happy with the clumsy logics anyhow.
                – RudiC
                7 hours ago
















              I'd stick to lower case variable names, but that's just style. I came up with the same logic.
              – glenn jackman
              7 hours ago




              I'd stick to lower case variable names, but that's just style. I came up with the same logic.
              – glenn jackman
              7 hours ago












              Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
              – glenn jackman
              7 hours ago





              Actually, there is a bug here: if the first line is less than one, the first condition will be false, so the the first number will not be printed. You need a separate rule for NR==1
              – glenn jackman
              7 hours ago













              I might recheck. I'm not too happy with the clumsy logics anyhow.
              – RudiC
              7 hours ago





              I might recheck. I'm not too happy with the clumsy logics anyhow.
              – RudiC
              7 hours ago











              up vote
              1
              down vote













              awk, with a different (more C-like) approach:



              awk ' do for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1); print s==e ? s : s","e while(r>0) ' file





              share|improve this answer


























                up vote
                1
                down vote













                awk, with a different (more C-like) approach:



                awk ' do for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1); print s==e ? s : s","e while(r>0) ' file





                share|improve this answer
























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  awk, with a different (more C-like) approach:



                  awk ' do for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1); print s==e ? s : s","e while(r>0) ' file





                  share|improve this answer














                  awk, with a different (more C-like) approach:



                  awk ' do for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1); print s==e ? s : s","e while(r>0) ' file






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 6 hours ago









                  don_crissti

                  47.2k15125155




                  47.2k15125155










                  answered 6 hours ago









                  mosvy

                  7176




                  7176



























                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f470073%2fhow-to-collapse-consecutive-numbers-into-ranges%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Comments

                      Popular posts from this blog

                      Long meetings (6-7 hours a day): Being “babysat” by supervisor

                      Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

                      Confectionery