How to collapse consecutive numbers into ranges?
Clash Royale CLAN TAG#URR8PPP
up vote
8
down vote
favorite
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
add a comment |Â
up vote
8
down vote
favorite
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
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
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
Sep 19 at 19:44
@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 liken
,n+1
,n+2
,n+3
and so on (Ã lan++
) up ton+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
Sep 19 at 20:21
Thank you for explaining whatconsecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify whatcombined into
means? For instance how you get9-12
,28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!
â TNT
Sep 20 at 9:15
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46
add a comment |Â
up vote
8
down vote
favorite
up vote
8
down vote
favorite
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
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
text-processing numeric-data
edited Sep 19 at 17:17
Jeff Schaller
33.2k849111
33.2k849111
asked Sep 19 at 17:16
don_crissti
47.5k15126155
47.5k15126155
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
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
Sep 19 at 19:44
@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 liken
,n+1
,n+2
,n+3
and so on (Ã lan++
) up ton+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
Sep 19 at 20:21
Thank you for explaining whatconsecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify whatcombined into
means? For instance how you get9-12
,28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!
â TNT
Sep 20 at 9:15
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46
add a comment |Â
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
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
Sep 19 at 19:44
@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 liken
,n+1
,n+2
,n+3
and so on (Ã lan++
) up ton+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
Sep 19 at 20:21
Thank you for explaining whatconsecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify whatcombined into
means? For instance how you get9-12
,28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!
â TNT
Sep 20 at 9:15
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
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
Sep 19 at 19:44
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
Sep 19 at 19:44
@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
Sep 19 at 20:21
@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
Sep 19 at 20:21
Thank you for explaining what
consecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify what combined into
means? For instance how you get 9-12
, 28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!â TNT
Sep 20 at 9:15
Thank you for explaining what
consecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify what combined into
means? For instance how you get 9-12
, 28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!â TNT
Sep 20 at 9:15
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46
add a comment |Â
12 Answers
12
active
oldest
votes
up vote
8
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()
'
add a comment |Â
up vote
5
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);
2
24,24
and33,33
is not quite what was requested...
â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
add a comment |Â
up vote
4
down vote
With dc
for the mental exercise:
dc -f "$1" -e '
[ q ]sB
z d 0 =B sc sa z sb
[ Sa lb 1 - d sb 0 <Z ]sZ
lZx
[ 1 sk lf 1 =O lk 1 =M ]sS
[ li p c 0 d sk sf ]sO
[ 2 sf lh d sj li 1 + !=O ]sQ
[ li n [,] n lj p c 0 sf ]sM
[ 0 sk lh sj ]sN
[ 1 sk lj lh 1 - =N lk 1 =M ]sR
[ 1 sf lh si ]sP
[ La sh lc 1 - sc lf 2 =R lf 1 =Q lf 0 =P lc 0 !=A ]sA
lAx
lSx
'
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
add a comment |Â
up vote
3
down vote
Another awk
approach (a variation of glenn's answer):
awk '
function output() print start (start != end? ","end : "")
end==$0-1 || end==$0 end=$0; next
end!="" output()
start=end=$0
END output() ' infile
add a comment |Â
up vote
3
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
the same thing, even less awk-ward:
awk 'BEGIN
for(r=getline; r>0;)
for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1);
print s==e ? s : s","e
exit -r
' file
Nice. In the interests of compactness,for(r=getline; r>0;)
could just befor(r=getline;r;)
â steve
Sep 21 at 18:56
And(r=getline)>0
could just be(r=getline)
â steve
Sep 21 at 18:56
1
@stevegetline
returns -1 on error (egEIO
)
â mosvy
Sep 21 at 19:02
1
@steve. That's why theexit -r
too -- that could be removed (awk will handle that itself on the next automaticgetline
) but I wanted the second version to be completely unmagical.
â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"
â steve
Sep 22 at 8:37
 |Â
show 1 more comment
up vote
3
down vote
Using Perl substitute with eval (Sorry for the obfuscation...):
perl -0pe 's/(d+)n(?=(d+))/ $1+1==$2 ? "$1," : $& /ge;
s/,.*,/,/g' ex
- first substitution creates lines with "," separated consecutive int sequences;
- second substitution, removes middle numbers.
add a comment |Â
up vote
2
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
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
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 forNR==1
â glenn jackman
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
add a comment |Â
up vote
2
down vote
An alternative in awk:
<infile sort -nu | awk '
l=p=$1
while ( (r=getline) >= 0 )
if ( $1 == p+1 ) p=$1; continue ;
print ( l==p ? l : l","p );
l=p=$1
if(r==0) break ;
if (r == -1 ) print "Unexpected error in reading file"; quit
'
On one line (no error check):
<infile awk 'l=p=$1while((r=getline)>=0)if($1==p+1)p=$1;continue;print(l==p?l:l","p);l=p=$1;if(r==0) break ;'
With comments (and pre-processing the file to ensure a sorted, unique list):
<infile sort -nu | awk '
l=p=$1 ## Only on the first line. The loop will read all lines.
## read all lines while there is no error.
while ( (r=getline) >= 0 )
## If present line ($1) follows previous line (p), continue.
if ( $1 == p+1 ) p=$1; continue ;
### Starting a new range ($1>p+1): print the previous range.
print ( l==p ? l : l","p );
## Save values in the variables left (l) and previous (p).
l=p=$1
## At the end of the file, break the loop.
if(r==0) break ;
## All lines have been processed or got an error.
if (r == -1 ) print "Unexpected error in reading file"; quit
'
add a comment |Â
up vote
2
down vote
Yet another awk
solution similar to the other:
#!/usr/bin/awk -f
function output()
# This function is called when a completed range needs to be
# outputted. It will use the global variables rstart and rend.
if (rend != "")
print rstart, rend
else
print rstart
# Output field separator is a comma.
BEGIN OFS = ","
# At the start, just set rstart and prev (the previous line's number) to
# the first number, then continue with the next line.
NR == 1 rstart = prev = $0; next
# Calculate the difference between this line and the previous. If it's
# 1, move the end of the current range here.
(diff = $0 - prev) == 1 rend = $0
# If the difference is more than one, then we're onto a new range.
# Output the range that we were processing and reset rstart and rend.
diff > 1
output()
rstart = $0
rend = ""
# Remember this line's number as prev before moving on to the next line.
prev = $0
# At the end, output the last range.
END output()
The rend
variable is not actually needed, but I wanted to keep as much range logic as possible away from the output()
function.
add a comment |Â
up vote
1
down vote
Ugly software tools bash
shell code, where file is the input file:
diff -y file <(seq $(head -1 file) $(tail -1 file)) | cut -f1 |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/nn+/n/g;s/^n//p'
Or with wdiff
:
wdiff -12 file <(seq $(head -1 file) $(tail -1 file) ) |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/=+nn//g;s/^n//p'
How these work: Make a gapless sequential list with seq
using the first and last numbers in the input file, (because file is already sorted), and diff
does most of the work. The sed
code is mainly just formatting, and replacing in-between numbers with a comma.
For a related problem, which is the inverse of this one, see: Finding gaps in sequential numbers
add a comment |Â
up vote
1
down vote
A nice discussion from 2001 on perlmonks.org, and adapted to read from STDIN or files named on the command line (as Perl is wont to do):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.6.0; # for (?? ... )
sub num2range
local $_ = join ',' => @_;
s/(?<!d)(d+)(?:,((??$++1))(?!d))+/$1-$+/g;
tr/-,/,n/;
return $_;
my @list;
chomp(@list = <>);
my $range = num2range(@list);
print "$rangen";
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
add a comment |Â
up vote
0
down vote
On a "Unix & Linux" site, a simple, readable, pure (bash) shell script feels most appropriate to me:
#!/bin/bash
inputfile=./input.txt
unset prev begin
while read num ; do
if [ "$prev" = "$((num-1))" ] ; then
prev=$num
else
if [ "$begin" ] ; then
[ "$begin" = "$prev" ] && echo "$prev" || echo "$begin,$prev"
fi
begin=$num
prev=$num
fi
done < $inputfile
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makesdc
a suitable tool for the job.
â don_crissti
yesterday
add a comment |Â
12 Answers
12
active
oldest
votes
12 Answers
12
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
8
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()
'
add a comment |Â
up vote
8
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()
'
add a comment |Â
up vote
8
down vote
up vote
8
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()
'
awk '
function output() print start (prev == start ? "" : ","prev)
NR == 1 start = prev = $1; next
$1 > prev+1 output(); start = $1
prev = $1
END output()
'
answered Sep 19 at 17:40
glenn jackman
48.3k365105
48.3k365105
add a comment |Â
add a comment |Â
up vote
5
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);
2
24,24
and33,33
is not quite what was requested...
â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
add a comment |Â
up vote
5
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);
2
24,24
and33,33
is not quite what was requested...
â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
add a comment |Â
up vote
5
down vote
up vote
5
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);
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);
edited Sep 19 at 20:40
answered Sep 19 at 18:01
Goro
6,16552763
6,16552763
2
24,24
and33,33
is not quite what was requested...
â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
add a comment |Â
2
24,24
and33,33
is not quite what was requested...
â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
2
2
24,24
and 33,33
is not quite what was requested...â RudiC
Sep 19 at 18:12
24,24
and 33,33
is not quite what was requested...â RudiC
Sep 19 at 18:12
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
As your awk approach is quite similar to glenn jackman's and mine, refer to those.
â RudiC
Sep 19 at 20:11
add a comment |Â
up vote
4
down vote
With dc
for the mental exercise:
dc -f "$1" -e '
[ q ]sB
z d 0 =B sc sa z sb
[ Sa lb 1 - d sb 0 <Z ]sZ
lZx
[ 1 sk lf 1 =O lk 1 =M ]sS
[ li p c 0 d sk sf ]sO
[ 2 sf lh d sj li 1 + !=O ]sQ
[ li n [,] n lj p c 0 sf ]sM
[ 0 sk lh sj ]sN
[ 1 sk lj lh 1 - =N lk 1 =M ]sR
[ 1 sf lh si ]sP
[ La sh lc 1 - sc lf 2 =R lf 1 =Q lf 0 =P lc 0 !=A ]sA
lAx
lSx
'
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
add a comment |Â
up vote
4
down vote
With dc
for the mental exercise:
dc -f "$1" -e '
[ q ]sB
z d 0 =B sc sa z sb
[ Sa lb 1 - d sb 0 <Z ]sZ
lZx
[ 1 sk lf 1 =O lk 1 =M ]sS
[ li p c 0 d sk sf ]sO
[ 2 sf lh d sj li 1 + !=O ]sQ
[ li n [,] n lj p c 0 sf ]sM
[ 0 sk lh sj ]sN
[ 1 sk lj lh 1 - =N lk 1 =M ]sR
[ 1 sf lh si ]sP
[ La sh lc 1 - sc lf 2 =R lf 1 =Q lf 0 =P lc 0 !=A ]sA
lAx
lSx
'
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
add a comment |Â
up vote
4
down vote
up vote
4
down vote
With dc
for the mental exercise:
dc -f "$1" -e '
[ q ]sB
z d 0 =B sc sa z sb
[ Sa lb 1 - d sb 0 <Z ]sZ
lZx
[ 1 sk lf 1 =O lk 1 =M ]sS
[ li p c 0 d sk sf ]sO
[ 2 sf lh d sj li 1 + !=O ]sQ
[ li n [,] n lj p c 0 sf ]sM
[ 0 sk lh sj ]sN
[ 1 sk lj lh 1 - =N lk 1 =M ]sR
[ 1 sf lh si ]sP
[ La sh lc 1 - sc lf 2 =R lf 1 =Q lf 0 =P lc 0 !=A ]sA
lAx
lSx
'
With dc
for the mental exercise:
dc -f "$1" -e '
[ q ]sB
z d 0 =B sc sa z sb
[ Sa lb 1 - d sb 0 <Z ]sZ
lZx
[ 1 sk lf 1 =O lk 1 =M ]sS
[ li p c 0 d sk sf ]sO
[ 2 sf lh d sj li 1 + !=O ]sQ
[ li n [,] n lj p c 0 sf ]sM
[ 0 sk lh sj ]sN
[ 1 sk lj lh 1 - =N lk 1 =M ]sR
[ 1 sf lh si ]sP
[ La sh lc 1 - sc lf 2 =R lf 1 =Q lf 0 =P lc 0 !=A ]sA
lAx
lSx
'
edited Sep 24 at 17:15
Jeff Schaller
33.2k849111
33.2k849111
answered Sep 21 at 18:19
ctac_
1,179116
1,179116
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
add a comment |Â
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
2
2
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
ð this is the kind of answer that makes you wish you could upvote twice...
â don_crissti
Sep 21 at 19:18
1
1
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
@don_crissti, if you're in to this sort of stuff, post the same question on codegolf.se and someone will implement it in Brainf**k.
â ilkkachu
Sep 24 at 21:12
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
lol this ****head (whoever he is) must hate me really bad if he downvoted your answer just because I said I liked it... Some pretty sick minds around here, I swear...
â don_crissti
yesterday
add a comment |Â
up vote
3
down vote
Another awk
approach (a variation of glenn's answer):
awk '
function output() print start (start != end? ","end : "")
end==$0-1 || end==$0 end=$0; next
end!="" output()
start=end=$0
END output() ' infile
add a comment |Â
up vote
3
down vote
Another awk
approach (a variation of glenn's answer):
awk '
function output() print start (start != end? ","end : "")
end==$0-1 || end==$0 end=$0; next
end!="" output()
start=end=$0
END output() ' infile
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Another awk
approach (a variation of glenn's answer):
awk '
function output() print start (start != end? ","end : "")
end==$0-1 || end==$0 end=$0; next
end!="" output()
start=end=$0
END output() ' infile
Another awk
approach (a variation of glenn's answer):
awk '
function output() print start (start != end? ","end : "")
end==$0-1 || end==$0 end=$0; next
end!="" output()
start=end=$0
END output() ' infile
edited Sep 20 at 6:52
answered Sep 19 at 17:47
ñÃÂsýù÷
16k92563
16k92563
add a comment |Â
add a comment |Â
up vote
3
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
the same thing, even less awk-ward:
awk 'BEGIN
for(r=getline; r>0;)
for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1);
print s==e ? s : s","e
exit -r
' file
Nice. In the interests of compactness,for(r=getline; r>0;)
could just befor(r=getline;r;)
â steve
Sep 21 at 18:56
And(r=getline)>0
could just be(r=getline)
â steve
Sep 21 at 18:56
1
@stevegetline
returns -1 on error (egEIO
)
â mosvy
Sep 21 at 19:02
1
@steve. That's why theexit -r
too -- that could be removed (awk will handle that itself on the next automaticgetline
) but I wanted the second version to be completely unmagical.
â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"
â steve
Sep 22 at 8:37
 |Â
show 1 more comment
up vote
3
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
the same thing, even less awk-ward:
awk 'BEGIN
for(r=getline; r>0;)
for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1);
print s==e ? s : s","e
exit -r
' file
Nice. In the interests of compactness,for(r=getline; r>0;)
could just befor(r=getline;r;)
â steve
Sep 21 at 18:56
And(r=getline)>0
could just be(r=getline)
â steve
Sep 21 at 18:56
1
@stevegetline
returns -1 on error (egEIO
)
â mosvy
Sep 21 at 19:02
1
@steve. That's why theexit -r
too -- that could be removed (awk will handle that itself on the next automaticgetline
) but I wanted the second version to be completely unmagical.
â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"
â steve
Sep 22 at 8:37
 |Â
show 1 more comment
up vote
3
down vote
up vote
3
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
the same thing, even less awk-ward:
awk 'BEGIN
for(r=getline; r>0;)
for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1);
print s==e ? s : s","e
exit -r
' file
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
the same thing, even less awk-ward:
awk 'BEGIN
for(r=getline; r>0;)
for(s=e=$1; (r=getline)>0 && $1<=e+1; e=$1);
print s==e ? s : s","e
exit -r
' file
edited Sep 20 at 20:39
answered Sep 19 at 18:46
mosvy
1,68719
1,68719
Nice. In the interests of compactness,for(r=getline; r>0;)
could just befor(r=getline;r;)
â steve
Sep 21 at 18:56
And(r=getline)>0
could just be(r=getline)
â steve
Sep 21 at 18:56
1
@stevegetline
returns -1 on error (egEIO
)
â mosvy
Sep 21 at 19:02
1
@steve. That's why theexit -r
too -- that could be removed (awk will handle that itself on the next automaticgetline
) but I wanted the second version to be completely unmagical.
â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"
â steve
Sep 22 at 8:37
 |Â
show 1 more comment
Nice. In the interests of compactness,for(r=getline; r>0;)
could just befor(r=getline;r;)
â steve
Sep 21 at 18:56
And(r=getline)>0
could just be(r=getline)
â steve
Sep 21 at 18:56
1
@stevegetline
returns -1 on error (egEIO
)
â mosvy
Sep 21 at 19:02
1
@steve. That's why theexit -r
too -- that could be removed (awk will handle that itself on the next automaticgetline
) but I wanted the second version to be completely unmagical.
â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"
â steve
Sep 22 at 8:37
Nice. In the interests of compactness,
for(r=getline; r>0;)
could just be for(r=getline;r;)
â steve
Sep 21 at 18:56
Nice. In the interests of compactness,
for(r=getline; r>0;)
could just be for(r=getline;r;)
â steve
Sep 21 at 18:56
And
(r=getline)>0
could just be (r=getline)
â steve
Sep 21 at 18:56
And
(r=getline)>0
could just be (r=getline)
â steve
Sep 21 at 18:56
1
1
@steve
getline
returns -1 on error (eg EIO
)â mosvy
Sep 21 at 19:02
@steve
getline
returns -1 on error (eg EIO
)â mosvy
Sep 21 at 19:02
1
1
@steve. That's why the
exit -r
too -- that could be removed (awk will handle that itself on the next automatic getline
) but I wanted the second version to be completely unmagical.â mosvy
Sep 21 at 19:14
@steve. That's why the
exit -r
too -- that could be removed (awk will handle that itself on the next automatic getline
) but I wanted the second version to be completely unmagical.â mosvy
Sep 21 at 19:14
on my gnu awk, getline returns zero on EIO. Example :
echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"â steve
Sep 22 at 8:37
on my gnu awk, getline returns zero on EIO. Example :
echo foo | awk 'BEGINa=getline;print a;a=getline;print a'
yields output of "1" followed by "0". Man page : "The getline command returns 1 on success, 0 on end of file, and -1 on an error"â steve
Sep 22 at 8:37
 |Â
show 1 more comment
up vote
3
down vote
Using Perl substitute with eval (Sorry for the obfuscation...):
perl -0pe 's/(d+)n(?=(d+))/ $1+1==$2 ? "$1," : $& /ge;
s/,.*,/,/g' ex
- first substitution creates lines with "," separated consecutive int sequences;
- second substitution, removes middle numbers.
add a comment |Â
up vote
3
down vote
Using Perl substitute with eval (Sorry for the obfuscation...):
perl -0pe 's/(d+)n(?=(d+))/ $1+1==$2 ? "$1," : $& /ge;
s/,.*,/,/g' ex
- first substitution creates lines with "," separated consecutive int sequences;
- second substitution, removes middle numbers.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Using Perl substitute with eval (Sorry for the obfuscation...):
perl -0pe 's/(d+)n(?=(d+))/ $1+1==$2 ? "$1," : $& /ge;
s/,.*,/,/g' ex
- first substitution creates lines with "," separated consecutive int sequences;
- second substitution, removes middle numbers.
Using Perl substitute with eval (Sorry for the obfuscation...):
perl -0pe 's/(d+)n(?=(d+))/ $1+1==$2 ? "$1," : $& /ge;
s/,.*,/,/g' ex
- first substitution creates lines with "," separated consecutive int sequences;
- second substitution, removes middle numbers.
edited Sep 24 at 15:06
answered Sep 24 at 14:44
JJoao
6,8311826
6,8311826
add a comment |Â
add a comment |Â
up vote
2
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
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
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 forNR==1
â glenn jackman
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
add a comment |Â
up vote
2
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
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
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 forNR==1
â glenn jackman
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
add a comment |Â
up vote
2
down vote
up vote
2
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
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
edited Sep 19 at 17:39
answered Sep 19 at 17:27
RudiC
1,6549
1,6549
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
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 forNR==1
â glenn jackman
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
add a comment |Â
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
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 forNR==1
â glenn jackman
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
I'd stick to lower case variable names, but that's just style. I came up with the same logic.
â glenn jackman
Sep 19 at 17:42
1
1
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
Sep 19 at 17:44
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
Sep 19 at 17:44
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
I might recheck. I'm not too happy with the clumsy logics anyhow.
â RudiC
Sep 19 at 18:06
add a comment |Â
up vote
2
down vote
An alternative in awk:
<infile sort -nu | awk '
l=p=$1
while ( (r=getline) >= 0 )
if ( $1 == p+1 ) p=$1; continue ;
print ( l==p ? l : l","p );
l=p=$1
if(r==0) break ;
if (r == -1 ) print "Unexpected error in reading file"; quit
'
On one line (no error check):
<infile awk 'l=p=$1while((r=getline)>=0)if($1==p+1)p=$1;continue;print(l==p?l:l","p);l=p=$1;if(r==0) break ;'
With comments (and pre-processing the file to ensure a sorted, unique list):
<infile sort -nu | awk '
l=p=$1 ## Only on the first line. The loop will read all lines.
## read all lines while there is no error.
while ( (r=getline) >= 0 )
## If present line ($1) follows previous line (p), continue.
if ( $1 == p+1 ) p=$1; continue ;
### Starting a new range ($1>p+1): print the previous range.
print ( l==p ? l : l","p );
## Save values in the variables left (l) and previous (p).
l=p=$1
## At the end of the file, break the loop.
if(r==0) break ;
## All lines have been processed or got an error.
if (r == -1 ) print "Unexpected error in reading file"; quit
'
add a comment |Â
up vote
2
down vote
An alternative in awk:
<infile sort -nu | awk '
l=p=$1
while ( (r=getline) >= 0 )
if ( $1 == p+1 ) p=$1; continue ;
print ( l==p ? l : l","p );
l=p=$1
if(r==0) break ;
if (r == -1 ) print "Unexpected error in reading file"; quit
'
On one line (no error check):
<infile awk 'l=p=$1while((r=getline)>=0)if($1==p+1)p=$1;continue;print(l==p?l:l","p);l=p=$1;if(r==0) break ;'
With comments (and pre-processing the file to ensure a sorted, unique list):
<infile sort -nu | awk '
l=p=$1 ## Only on the first line. The loop will read all lines.
## read all lines while there is no error.
while ( (r=getline) >= 0 )
## If present line ($1) follows previous line (p), continue.
if ( $1 == p+1 ) p=$1; continue ;
### Starting a new range ($1>p+1): print the previous range.
print ( l==p ? l : l","p );
## Save values in the variables left (l) and previous (p).
l=p=$1
## At the end of the file, break the loop.
if(r==0) break ;
## All lines have been processed or got an error.
if (r == -1 ) print "Unexpected error in reading file"; quit
'
add a comment |Â
up vote
2
down vote
up vote
2
down vote
An alternative in awk:
<infile sort -nu | awk '
l=p=$1
while ( (r=getline) >= 0 )
if ( $1 == p+1 ) p=$1; continue ;
print ( l==p ? l : l","p );
l=p=$1
if(r==0) break ;
if (r == -1 ) print "Unexpected error in reading file"; quit
'
On one line (no error check):
<infile awk 'l=p=$1while((r=getline)>=0)if($1==p+1)p=$1;continue;print(l==p?l:l","p);l=p=$1;if(r==0) break ;'
With comments (and pre-processing the file to ensure a sorted, unique list):
<infile sort -nu | awk '
l=p=$1 ## Only on the first line. The loop will read all lines.
## read all lines while there is no error.
while ( (r=getline) >= 0 )
## If present line ($1) follows previous line (p), continue.
if ( $1 == p+1 ) p=$1; continue ;
### Starting a new range ($1>p+1): print the previous range.
print ( l==p ? l : l","p );
## Save values in the variables left (l) and previous (p).
l=p=$1
## At the end of the file, break the loop.
if(r==0) break ;
## All lines have been processed or got an error.
if (r == -1 ) print "Unexpected error in reading file"; quit
'
An alternative in awk:
<infile sort -nu | awk '
l=p=$1
while ( (r=getline) >= 0 )
if ( $1 == p+1 ) p=$1; continue ;
print ( l==p ? l : l","p );
l=p=$1
if(r==0) break ;
if (r == -1 ) print "Unexpected error in reading file"; quit
'
On one line (no error check):
<infile awk 'l=p=$1while((r=getline)>=0)if($1==p+1)p=$1;continue;print(l==p?l:l","p);l=p=$1;if(r==0) break ;'
With comments (and pre-processing the file to ensure a sorted, unique list):
<infile sort -nu | awk '
l=p=$1 ## Only on the first line. The loop will read all lines.
## read all lines while there is no error.
while ( (r=getline) >= 0 )
## If present line ($1) follows previous line (p), continue.
if ( $1 == p+1 ) p=$1; continue ;
### Starting a new range ($1>p+1): print the previous range.
print ( l==p ? l : l","p );
## Save values in the variables left (l) and previous (p).
l=p=$1
## At the end of the file, break the loop.
if(r==0) break ;
## All lines have been processed or got an error.
if (r == -1 ) print "Unexpected error in reading file"; quit
'
edited Sep 25 at 23:43
answered Sep 23 at 3:38
Isaac
7,51911037
7,51911037
add a comment |Â
add a comment |Â
up vote
2
down vote
Yet another awk
solution similar to the other:
#!/usr/bin/awk -f
function output()
# This function is called when a completed range needs to be
# outputted. It will use the global variables rstart and rend.
if (rend != "")
print rstart, rend
else
print rstart
# Output field separator is a comma.
BEGIN OFS = ","
# At the start, just set rstart and prev (the previous line's number) to
# the first number, then continue with the next line.
NR == 1 rstart = prev = $0; next
# Calculate the difference between this line and the previous. If it's
# 1, move the end of the current range here.
(diff = $0 - prev) == 1 rend = $0
# If the difference is more than one, then we're onto a new range.
# Output the range that we were processing and reset rstart and rend.
diff > 1
output()
rstart = $0
rend = ""
# Remember this line's number as prev before moving on to the next line.
prev = $0
# At the end, output the last range.
END output()
The rend
variable is not actually needed, but I wanted to keep as much range logic as possible away from the output()
function.
add a comment |Â
up vote
2
down vote
Yet another awk
solution similar to the other:
#!/usr/bin/awk -f
function output()
# This function is called when a completed range needs to be
# outputted. It will use the global variables rstart and rend.
if (rend != "")
print rstart, rend
else
print rstart
# Output field separator is a comma.
BEGIN OFS = ","
# At the start, just set rstart and prev (the previous line's number) to
# the first number, then continue with the next line.
NR == 1 rstart = prev = $0; next
# Calculate the difference between this line and the previous. If it's
# 1, move the end of the current range here.
(diff = $0 - prev) == 1 rend = $0
# If the difference is more than one, then we're onto a new range.
# Output the range that we were processing and reset rstart and rend.
diff > 1
output()
rstart = $0
rend = ""
# Remember this line's number as prev before moving on to the next line.
prev = $0
# At the end, output the last range.
END output()
The rend
variable is not actually needed, but I wanted to keep as much range logic as possible away from the output()
function.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
Yet another awk
solution similar to the other:
#!/usr/bin/awk -f
function output()
# This function is called when a completed range needs to be
# outputted. It will use the global variables rstart and rend.
if (rend != "")
print rstart, rend
else
print rstart
# Output field separator is a comma.
BEGIN OFS = ","
# At the start, just set rstart and prev (the previous line's number) to
# the first number, then continue with the next line.
NR == 1 rstart = prev = $0; next
# Calculate the difference between this line and the previous. If it's
# 1, move the end of the current range here.
(diff = $0 - prev) == 1 rend = $0
# If the difference is more than one, then we're onto a new range.
# Output the range that we were processing and reset rstart and rend.
diff > 1
output()
rstart = $0
rend = ""
# Remember this line's number as prev before moving on to the next line.
prev = $0
# At the end, output the last range.
END output()
The rend
variable is not actually needed, but I wanted to keep as much range logic as possible away from the output()
function.
Yet another awk
solution similar to the other:
#!/usr/bin/awk -f
function output()
# This function is called when a completed range needs to be
# outputted. It will use the global variables rstart and rend.
if (rend != "")
print rstart, rend
else
print rstart
# Output field separator is a comma.
BEGIN OFS = ","
# At the start, just set rstart and prev (the previous line's number) to
# the first number, then continue with the next line.
NR == 1 rstart = prev = $0; next
# Calculate the difference between this line and the previous. If it's
# 1, move the end of the current range here.
(diff = $0 - prev) == 1 rend = $0
# If the difference is more than one, then we're onto a new range.
# Output the range that we were processing and reset rstart and rend.
diff > 1
output()
rstart = $0
rend = ""
# Remember this line's number as prev before moving on to the next line.
prev = $0
# At the end, output the last range.
END output()
The rend
variable is not actually needed, but I wanted to keep as much range logic as possible away from the output()
function.
edited Sep 26 at 0:03
muru
33.8k577146
33.8k577146
answered Sep 20 at 9:48
Kusalananda
108k14209332
108k14209332
add a comment |Â
add a comment |Â
up vote
1
down vote
Ugly software tools bash
shell code, where file is the input file:
diff -y file <(seq $(head -1 file) $(tail -1 file)) | cut -f1 |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/nn+/n/g;s/^n//p'
Or with wdiff
:
wdiff -12 file <(seq $(head -1 file) $(tail -1 file) ) |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/=+nn//g;s/^n//p'
How these work: Make a gapless sequential list with seq
using the first and last numbers in the input file, (because file is already sorted), and diff
does most of the work. The sed
code is mainly just formatting, and replacing in-between numbers with a comma.
For a related problem, which is the inverse of this one, see: Finding gaps in sequential numbers
add a comment |Â
up vote
1
down vote
Ugly software tools bash
shell code, where file is the input file:
diff -y file <(seq $(head -1 file) $(tail -1 file)) | cut -f1 |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/nn+/n/g;s/^n//p'
Or with wdiff
:
wdiff -12 file <(seq $(head -1 file) $(tail -1 file) ) |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/=+nn//g;s/^n//p'
How these work: Make a gapless sequential list with seq
using the first and last numbers in the input file, (because file is already sorted), and diff
does most of the work. The sed
code is mainly just formatting, and replacing in-between numbers with a comma.
For a related problem, which is the inverse of this one, see: Finding gaps in sequential numbers
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Ugly software tools bash
shell code, where file is the input file:
diff -y file <(seq $(head -1 file) $(tail -1 file)) | cut -f1 |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/nn+/n/g;s/^n//p'
Or with wdiff
:
wdiff -12 file <(seq $(head -1 file) $(tail -1 file) ) |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/=+nn//g;s/^n//p'
How these work: Make a gapless sequential list with seq
using the first and last numbers in the input file, (because file is already sorted), and diff
does most of the work. The sed
code is mainly just formatting, and replacing in-between numbers with a comma.
For a related problem, which is the inverse of this one, see: Finding gaps in sequential numbers
Ugly software tools bash
shell code, where file is the input file:
diff -y file <(seq $(head -1 file) $(tail -1 file)) | cut -f1 |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/nn+/n/g;s/^n//p'
Or with wdiff
:
wdiff -12 file <(seq $(head -1 file) $(tail -1 file) ) |
sed -En 'H;$x;s/([0-9]+)n([0-9]+n)*([0-9]+)/1,3/g;s/=+nn//g;s/^n//p'
How these work: Make a gapless sequential list with seq
using the first and last numbers in the input file, (because file is already sorted), and diff
does most of the work. The sed
code is mainly just formatting, and replacing in-between numbers with a comma.
For a related problem, which is the inverse of this one, see: Finding gaps in sequential numbers
edited Sep 27 at 16:25
answered Sep 24 at 15:48
agc
4,3221935
4,3221935
add a comment |Â
add a comment |Â
up vote
1
down vote
A nice discussion from 2001 on perlmonks.org, and adapted to read from STDIN or files named on the command line (as Perl is wont to do):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.6.0; # for (?? ... )
sub num2range
local $_ = join ',' => @_;
s/(?<!d)(d+)(?:,((??$++1))(?!d))+/$1-$+/g;
tr/-,/,n/;
return $_;
my @list;
chomp(@list = <>);
my $range = num2range(@list);
print "$rangen";
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
add a comment |Â
up vote
1
down vote
A nice discussion from 2001 on perlmonks.org, and adapted to read from STDIN or files named on the command line (as Perl is wont to do):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.6.0; # for (?? ... )
sub num2range
local $_ = join ',' => @_;
s/(?<!d)(d+)(?:,((??$++1))(?!d))+/$1-$+/g;
tr/-,/,n/;
return $_;
my @list;
chomp(@list = <>);
my $range = num2range(@list);
print "$rangen";
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
add a comment |Â
up vote
1
down vote
up vote
1
down vote
A nice discussion from 2001 on perlmonks.org, and adapted to read from STDIN or files named on the command line (as Perl is wont to do):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.6.0; # for (?? ... )
sub num2range
local $_ = join ',' => @_;
s/(?<!d)(d+)(?:,((??$++1))(?!d))+/$1-$+/g;
tr/-,/,n/;
return $_;
my @list;
chomp(@list = <>);
my $range = num2range(@list);
print "$rangen";
A nice discussion from 2001 on perlmonks.org, and adapted to read from STDIN or files named on the command line (as Perl is wont to do):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.6.0; # for (?? ... )
sub num2range
local $_ = join ',' => @_;
s/(?<!d)(d+)(?:,((??$++1))(?!d))+/$1-$+/g;
tr/-,/,n/;
return $_;
my @list;
chomp(@list = <>);
my $range = num2range(@list);
print "$rangen";
edited Sep 28 at 13:59
answered Sep 27 at 9:53
Quantum Mechanic
113
113
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
add a comment |Â
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
@don_crissti Done.
â Quantum Mechanic
Sep 28 at 14:00
add a comment |Â
up vote
0
down vote
On a "Unix & Linux" site, a simple, readable, pure (bash) shell script feels most appropriate to me:
#!/bin/bash
inputfile=./input.txt
unset prev begin
while read num ; do
if [ "$prev" = "$((num-1))" ] ; then
prev=$num
else
if [ "$begin" ] ; then
[ "$begin" = "$prev" ] && echo "$prev" || echo "$begin,$prev"
fi
begin=$num
prev=$num
fi
done < $inputfile
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makesdc
a suitable tool for the job.
â don_crissti
yesterday
add a comment |Â
up vote
0
down vote
On a "Unix & Linux" site, a simple, readable, pure (bash) shell script feels most appropriate to me:
#!/bin/bash
inputfile=./input.txt
unset prev begin
while read num ; do
if [ "$prev" = "$((num-1))" ] ; then
prev=$num
else
if [ "$begin" ] ; then
[ "$begin" = "$prev" ] && echo "$prev" || echo "$begin,$prev"
fi
begin=$num
prev=$num
fi
done < $inputfile
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makesdc
a suitable tool for the job.
â don_crissti
yesterday
add a comment |Â
up vote
0
down vote
up vote
0
down vote
On a "Unix & Linux" site, a simple, readable, pure (bash) shell script feels most appropriate to me:
#!/bin/bash
inputfile=./input.txt
unset prev begin
while read num ; do
if [ "$prev" = "$((num-1))" ] ; then
prev=$num
else
if [ "$begin" ] ; then
[ "$begin" = "$prev" ] && echo "$prev" || echo "$begin,$prev"
fi
begin=$num
prev=$num
fi
done < $inputfile
On a "Unix & Linux" site, a simple, readable, pure (bash) shell script feels most appropriate to me:
#!/bin/bash
inputfile=./input.txt
unset prev begin
while read num ; do
if [ "$prev" = "$((num-1))" ] ; then
prev=$num
else
if [ "$begin" ] ; then
[ "$begin" = "$prev" ] && echo "$prev" || echo "$begin,$prev"
fi
begin=$num
prev=$num
fi
done < $inputfile
edited yesterday
answered yesterday
Hkoof
93266
93266
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makesdc
a suitable tool for the job.
â don_crissti
yesterday
add a comment |Â
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makesdc
a suitable tool for the job.
â don_crissti
yesterday
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
Sorry, I never upvote answers that use shell loops to process text: it is not only wrong, it's also damn slow to do it with shell loops; take-home message: if you're using a shell loop to process text then you're doing it wrong.
â don_crissti
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
How come to you 'dc' is the right tool to process text?
â Hkoof
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makes
dc
a suitable tool for the job.â don_crissti
yesterday
The text in this particular case consists of numbers and the task involves arithmetic which makes
dc
a suitable tool for the job.â don_crissti
yesterday
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Very nice question, but would benefit from some clarifications for newbies. Please !
â TNT
Sep 19 at 17:46
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
Sep 19 at 19:44
@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 (Ã lan++
) up ton+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
Sep 19 at 20:21
Thank you for explaining what
consecutive
means and it is, indeed, has the same meaning in all languages. Would you please clarify whatcombined into
means? For instance how you get9-12
,28-29
. I am not a genius mathematician nor a programmer. As a reviewer or reader, the question must be clear for general people. Thank you for any additional clarifications!â TNT
Sep 20 at 9:15
@don_crissti Any specific requirements for the +50 bonus? Or: do you have already answer selected in your mind?
â Isaac
Sep 25 at 23:46