Стенограмма интерактивного J сеанса (ввод пользователя имеет отступ с 3 пробелами, текст в полях ASCII - вывод J):
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 |
+-----------------------------------------------------------+
Читаемый и элегантный в глазах смотрящего: D
Это было хорошее упражнение! Он предлагает следующий сегмент 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;
}
Добавление
На простом английском языке этот алгоритм находит все элементы, где предыдущий элемент не на единицу меньше, использует их для нижних границ; находит все элементы, у которых следующий элемент не больше, использует их для верхних границ; и объединяет два списка по пунктам.
Поскольку J довольно неясен, вот краткое объяснение того, как работает этот код:
x /: y
сортирует массив x
по y
. ~
может превратить двоичный глагол в возвратную монаду, поэтому /:~
означает «сортировать массив по себе».
3 : '...'
объявляет монадический глагол (способ J сказать «функция, принимающая один аргумент»). @
означает композицию функции, поэтому g =: 3 : '...' @ /:~
означает "g
установлена для функции, которую мы определяем, но с ее аргументом, отсортированным первым". "1
говорит, что мы работаем с массивами, а не с таблицами или чем-то более высокой размерности.
Примечание: y
- это всегда имя единственного аргумента монадического глагола.
{.
принимает первый элемент массива (head), а }:
принимает все, кроме последнего (curtail). ({.,}:)y
эффективно дублирует первый элемент y
и обрезает последний элемент. 1+({.,}:)y
добавляет 1 ко всему, и ~:
сравнивает два массива: true, где они различны, и false, где они одинаковые, поэтому y~:1+({.,}:)y
- это массив, истинный во всех индексах y
, где Элемент не равен ни на один больше, чем элемент, который предшествовал ему. (y~:1+({.,}:)y)#y
выбирает все элементы y
, если свойство, указанное в предыдущем предложении, имеет значение true.
Аналогично, }.
принимает все, кроме первого элемента массива (behead), а {:
- последний (tail), поэтому }.y,{:y
- все, кроме первого элемента y
, с последним элементом дублируется. (}.y,{:y)-1
вычитает 1 для всего этого, и снова ~:
сравнивает два массива поэлементно для неравенства, в то время как #
выбирает.
,.
объединяет два массива в массив из двух элементов. ~.
нумерует список (удаляет дубликаты) и получает ранг "1
, поэтому он работает с внутренними двухэлементными массивами, а не с массивом верхнего уровня. Это @
, составленный из <
, который помещает каждый вложенный массив в прямоугольник (в противном случае J снова расширит каждый вложенный массив для формирования 2D-таблицы).
g2
- это беспорядок в боксах и распаковках (в противном случае J будет заполнять строки одинаковой длины), и это довольно неинтересно.