2010-06-06 2 views
4

Я некоторое время работал над функцией J, которая должна сканировать список и помещать последовательные копии элемента в отдельные, объединенные поля. Мои усилия приняли меня, насколько функцииАбстрактные структуры ячеек массива в 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:) и применить его к оригиналу список ввода. (т. е. «Этот массив с боксами здесь имеет первый элемент, помещенный на глубину один, второй элемент, помещенный на первой, третьей, четвертой и пятой элементах, помещенных вместе на глубину 1, ..., поэтому возьмите этот список без списка и поместим его так же ».) Я попытался обмануть ;., S:, L:, L. и &., чтобы произвести это поведение, но мне не повезло. Есть ли какой-то оператор или принцип, который мне не хватает, чтобы это произошло? Меня не удивило бы, если бы я задумался над всей проблемой, но у меня заканчиваются идеи.

РЕДАКТИРОВАТЬ:

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

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

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

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

ответ

2

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

(<;.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). В качестве альтернативы вы можете также молчаливо записать это как fork (f g ]) s.

Chapter 9 of "Learning J" подробно обсуждает эту тему, если вы хотите узнать больше.

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

+0

Так вот как вы это делаете! Я провел несколько дней, собираясь с документацией, пытаясь сделать J применимыми к элементам элементы с использованием логического вывода. Спасибо за помощь. – estanford

+0

Добро пожаловать. Оглядываясь на это снова, я, вероятно, должен * упомянуть, что это использует __dyadic__ cut ('; .2') вместо монадического использования разреза в вашем исходном коде. И последнее замечание: если бы мы пошли на краткость кода (а также ясность, imo), я бы, вероятно, написал это, используя вариант cut-1 (вместо cut-2), который разбивается на ведущие 1s: '(<;. 1 ~ 1,2 & (~:/\)) '- приятный и сочный! – earl

0

Эта версия функции, которая у меня была в ум лучше, но все же не достаточно тихий, чтобы быть совершенным. (По крайней мере, он не задает вопрос о другой проблеме по дороге, во всяком случае.) Как только я выясню, как представить логику этого цикла 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 
) 

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

1

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

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

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