Абстрагирование структур массива в штучной упаковке в J - PullRequest
4 голосов
/ 06 июня 2010

Я некоторое время работал над функцией J, которая должна сканировать список и помещать последовательные копии элемента в отдельные соединенные блоки. Мои усилия привели меня к функции

(<;. 2) ((2&(~:/\)),1:)

, который проверяет последовательные записи списка на неравенство, возвращает список логических значений и разрезает список на блоки, которые заканчиваются каждый раз, когда появляется число 1. Вот пример приложения:

   (<;. 2) ((2&(~:/\)),1:) 1 2 3 3 3 4 1 1 1
+-+-+-----+-+-----+
|1|1|0 0 1|1|0 0 1|
+-+-+-----+-+-----+

Задача была бы завершена, если бы я мог тогда заменить все эти логические значения на соответствующие значения во входном аргументе. Я искал какую-то загадочную функцию, которая позволила бы мне сделать что-то вроде

   final =: mysteryfunction @ (<;. 2) ((2&(~:/\)),1:)

   final 1 2 3 3 3 4 1 1 1    
+-+-+-----+-+-----+
|1|2|3 3 3|4|1 1 1|
+-+-+-----+-+-----+

В идеальной ситуации был бы какой-то способ абстрактно представить шаблон вложения, сгенерированный (<;. 2) ((2&(~:/\)),1:), и применить его к исходному списку ввода. (т. е. «Этот штучный массив здесь имеет первый элемент, заключенный в бок на глубине один, второй элемент, заключенный в бок на глубине один, третий, четвертый и пятый элементы, заключенные в бок на глубине один, ... и упаковать его таким же образом. ") Я пытался дурачиться с ;., S:, L:, L. и &., чтобы произвести такое поведение, но мне не повезло. Есть ли какой-то оператор или принцип, который я упускаю, чтобы это могло произойти? Меня не удивило бы, если бы я переосмыслил весь вопрос, но у меня заканчиваются идеи.

EDIT:

На данный момент единственное рабочее решение, которое у меня есть, это:

isduplicate =: ((2&(~:/\)),1:)

testfun =: 3 : 0
numduplicates =. #S:0 ((<;.2) isduplicate y)
distinctboxes =. <"0 (isduplicate#]) y
numduplicates # each distinctboxes
)

Это двухэтапный процесс генерации кодировки длин серий, а затем отмены кодирования без избавления от полей. Поскольку я изначально делаю это с целью решения 99 задач в тандеме с использованием J и Haskell, мне кажется, что мне нужно задаться вопросом, решу ли я проблему 9, сначала решив проблему 12.

Ответы [ 3 ]

2 голосов
/ 14 июня 2010

Ты почти у цели. Добавьте ~ и поместите скобки по-другому, вот и все:

   (<;.2~ (2&(~:/\) , 1:)) 1 2 3 3 3 4 1 1 1
┌─┬─┬─────┬─┬─────┐
│1│2│3 3 3│4│1 1 1│
└─┴─┴─────┴─┴─────┘

Краткое объяснение / иллюстрация:

   s =: 1 2 3 3 3 4 1 1 1

   f =: 2&(~:/\) , 1:
   f s
1 1 0 0 1 1 0 0 1

   g =: <;.2

   (f s) g s
┌─┬─┬─────┬─┬─────┐
│1│2│3 3 3│4│1 1 1│
└─┴─┴─────┴─┴─────┘

Теперь, когда окончательный (f s) g s, иногда называемый «левым крючком», можно записать (g~ f) s (наречие ~ называется «пассивным» в J, аналог Haskell будет flip). В качестве альтернативы вы можете также молчаливо написать это как разветвление (f g ]) s.

Глава 9 «Обучение J» подробно обсуждает эту тему, если вы хотите узнать больше.

Обновление : Ранее я использовал (</.~ (+/\&(1,(2&(~:/\))))) на основе группировки, но ваш оригинальный подход на основе вырезов более элегантен (и короче), чем этот. Поскольку это действительно касается левого хука, я обновил, чтобы использовать ваш подход напрямую.

1 голос
/ 14 июня 2010

Я думаю, что вы обдумываете это. Это должно быть полностью молчаливым? Вот что я только что скинул вместе:

   s<;.2~  ((2&(~:/\)),1:) s=:1 2 3 3 3 4 1 1 1
┌─┬─┬─────┬─┬─────┐
│1│2│3 3 3│4│1 1 1│
└─┴─┴─────┴─┴─────┘

Очевидно, он просто назначает входной список s, а затем помещает его в выражение ;.. Если он должен быть полностью молчаливым, я уверен, что вы можете помассировать его, чтобы вывести список ввода в логический список, а затем использовать что-то вроде {. < ;.2 {: для получения результата.

0 голосов
/ 06 июня 2010

Эта версия функции, которую я имел в виду, лучше, но все же недостаточно молчалива, чтобы быть совершенной. (По крайней мере, по крайней мере, это не вызывает вопроса о другой проблеме в будущем.) Как только я пойму, как представить логику этого цикла while как молчаливое выражение, я буду в порядке.

NB. boxmerge takes a boxed argument and razes the first two
NB. elements together into a new box.
boxmerge =: [:}.]1}~[:<[:;2&{.

NB. conseq checks to see whether the first two boxes of a boxed
NB. array contain the same distinct element. (By assumption, each
NB. box contains only one distinct element.) The name is an
NB. abbreviation of the question, "consecutive boxes equal?"
conseq =: [:=/[:~.&.>2&{.

partfun =: ]`(boxmerge)@.conseq ^:_

listpack =: 3 : 0
mylist =. y
listbin =. >a:
while. (mylist -: (>a:)) = 0 do.
 newlist =. partfun mylist
 listbin =. listbin,{. newlist
 mylist =. }. newlist
end.
listbin
)

Идея цикла while заключается в применении partfun к списку, перемещении его головы в другой список, обезглавливании исходного списка и продолжайте делать это до тех пор, пока исходный список не будет полностью очищен. Я чувствую, что действительно должен быть способ представить эту логику с помощью неявных выражений. (На самом деле, я думаю, что я даже видел это в онлайн-документации.) Я просто не могу вспомнить соответствующую последовательность ^:, $: и @., которые мне нужно поставить последний гвоздь в гробу.

...