By which I mean this:
Given the input set of numbers:
1,2,3,4,5 becomes \"1-5\".
1,2,3,5,7,9,10,11,12,14 becomes \"1-3, 5, 7, 9-12, 14\"
This is
Transcript of an interactive J session (user input is indented 3 spaces, text in ASCII boxes is J output):
g =: 3 : '<@~."1((y~:1+({.,}:)y)#y),.(y~:(}.y,{:y)-1)#y'@/:~"1
g 1 2 3 4 5
+---+
|1 5|
+---+
g 1 2 3 5 7 9 10 11 12 14
+---+-+-+----+--+
|1 3|5|7|9 12|14|
+---+-+-+----+--+
g 12 2 14 9 1 3 10 5 11 7
+---+-+-+----+--+
|1 3|5|7|9 12|14|
+---+-+-+----+--+
g2 =: 4 : '<(>x),'' '',>y'/@:>@:(4 :'<(>x),''-'',>y'/&.>)@((<@":)"0&.>@g)
g2 12 2 14 9 1 3 10 5 11 7
+---------------+
|1-3 5 7 9-12 14|
+---------------+
(;g2) 5 1 20 $ (i.100) /: ? 100 $ 100
+-----------------------------------------------------------+
|20 39 82 33 72 93 15 30 85 24 97 60 87 44 77 29 58 69 78 43|
| |
|67 89 17 63 34 41 53 37 61 18 88 70 91 13 19 65 99 81 3 62|
| |
|31 32 6 11 23 94 16 73 76 7 0 75 98 27 66 28 50 9 22 38|
| |
|25 42 86 5 55 64 79 35 36 14 52 2 57 12 46 80 83 84 90 56|
| |
| 8 96 4 10 49 71 21 54 48 51 26 40 95 1 68 47 59 74 92 45|
+-----------------------------------------------------------+
|15 20 24 29-30 33 39 43-44 58 60 69 72 77-78 82 85 87 93 97|
+-----------------------------------------------------------+
|3 13 17-19 34 37 41 53 61-63 65 67 70 81 88-89 91 99 |
+-----------------------------------------------------------+
|0 6-7 9 11 16 22-23 27-28 31-32 38 50 66 73 75-76 94 98 |
+-----------------------------------------------------------+
|2 5 12 14 25 35-36 42 46 52 55-57 64 79-80 83-84 86 90 |
+-----------------------------------------------------------+
|1 4 8 10 21 26 40 45 47-49 51 54 59 68 71 74 92 95-96 |
+-----------------------------------------------------------+
Readable and elegant are in the eye of the beholder :D
That was a good exercise! It suggests the following segment of Perl:
sub g {
my ($i, @r, @s) = 0, local @_ = sort {$a<=>$b} @_;
$_ && $_[$_-1]+1 == $_[$_] || push(@r, $_[$_]),
$_<$#_ && $_[$_+1]-1 == $_[$_] || push(@s, $_[$_]) for 0..$#_;
join ' ', map {$_ == $s[$i++] ? $_ : "$_-$s[$i-1]"} @r;
}
In plain English, this algorithm finds all items where the previous item is not one less, uses them for the lower bounds; finds all items where the next item is not one greater, uses them for the upper bounds; and combines the two lists together item-by-item.
Since J is pretty obscure, here's a short explanation of how that code works:
x /: y
sorts the array x
on y
. ~
can make a dyadic verb into a reflexive monad, so /:~
means "sort an array on itself".
3 : '...'
declares a monadic verb (J's way of saying "function taking one argument"). @
means function composition, so g =: 3 : '...' @ /:~
means "g
is set to the function we're defining, but with its argument sorted first". "1
says that we operate on arrays, not tables or anything of higher dimensionality.
Note: y
is always the name of the only argument to a monadic verb.
{.
takes the first element of an array (head) and }:
takes all but the last (curtail). ({.,}:)y
effectively duplicates the first element of y
and lops off the last element. 1+({.,}:)y
adds 1 to it all, and ~:
compares two arrays, true wherever they are different and false wherever they are the same, so y~:1+({.,}:)y
is an array that is true in all the indices of y
where an element is not equal to one more than the element that preceded it. (y~:1+({.,}:)y)#y
selects all elements of y
where the property stated in the previous sentence is true.
Similarly, }.
takes all but the first element of an array (behead) and {:
takes the last (tail), so }.y,{:y
is all but the first element of y
, with the last element duplicated. (}.y,{:y)-1
subtracts 1 to it all, and again ~:
compares two arrays item-wise for non-equality while #
picks.
,.
zips the two arrays together, into an array of two-element arrays. ~.
nubs a list (eliminates duplicates), and is given the "1
rank, so it operates on the inner two-element arrays rather than the top-level array. This is @
composed with <
, which puts each subarray into a box (otherwise J will extend each subarray again to form a 2D table).
g2
is a mess of boxing and unboxing (otherwise J will pad strings to equal length), and is pretty uninteresting.