Цепные глаголы в J - PullRequest
       4

Цепные глаголы в J

6 голосов
/ 02 августа 2011

Предположим, в штучной упаковке матрица, содержащая различные типы:

matrix =: ('abc';'defgh';23),:('foo';'bar';45)
matrix
+---+-----+--+
|abc|defgh|23|
+---+-----+--+
|foo|bar  |45|
+---+-----+--+

И дескриптор столбца:

columnTypes =: 'string';'string';'num'

Я хочу применять глаголы к этой матрице по столбцам в соответствии с типами. Я буду использовать глаголы DoString и DoNum:

chain =: (('string';'num') i. columnTypes) { DoString`DoNum

EDIT: дескрипторы столбцов важны, решение о том, какой глагол использовать, основано на них, не на самом типе . В действительности у меня может быть несколько типов строк, чисел и даже дат (которые будут числовыми в J).

Как мне применить chain к каждой строке matrix? Сами глаголы могут позаботиться о том, передано ли значение в штучной упаковке или нет, это нормально. Кроме того, я бы предпочел избежать транспонирования матрицы (|:), так как она может быть довольно большой.

Ответы [ 3 ]

5 голосов
/ 09 июля 2013

Стандартный метод для этого:

  1. Преобразование структуры, ориентированной на строки (ячейки), в структуру, ориентированную на столбцы

  2. Применить правильный глагол к каждому столбцу (только один раз)

Шаг (1) прост. Шаг (2) также прост, но не так очевиден. Есть небольшая хитрость, которая помогает.

Хитрость заключается в том, что ряд примитивных операторов принимают герунду в качестве левого аргумента и создают функцию, которая циклически обходит герунду, применяя каждый глагол по очереди. ИМО, самый полезный оператор в этой категории - ;.. Вот пример реализации, использующей его:

Шаг (0), входы:

   matrix      =:  ('abc';'defgh';23),:('foo';'bar';45)

   columnTypes =:  'string';'string';'num'

   DoString    =:  toupper
   DoNum       =:  0&j.

   matrix
+---+-----+--+
|abc|defgh|23|
+---+-----+--+
|foo|bar  |45|
+---+-----+--+

Шаг (1), сбор данных:

   columnify   =:  <@:>"1@:|: :. rowify =: <"_1&>
   columnify matrix
+---+-----+-----+
|abc|defgh|23 45|
|foo|bar  |     |
+---+-----+-----+

Обратите внимание, что столбец columnify снабжен обратным знаком, который приведет к повторной «сортировке» данных, хотя вы не должны этого делать: см. Ниже.

Шаг (2), примените правильный глагол к каждому столбцу (ровно один раз), используя функцию циклического глагола ;.:

   homogenize  =:  ({. foo&.>@:{.`'') [^:('foo'-:])L:0~ ]
   chain       =:  DoString`DoNum`] homogenize@{~  ('string';'num')&i.  

Обратите внимание, что преобразованием по умолчанию для неизвестных типов столбцов является функция тождества, ].

Глагол homogenize нормализует ввод и вывод каждого процессора столбца (т. Е. Абстрагирует предварительную и последующую обработку, так что пользователю нужно только обеспечить динамическое «ядро» преобразования). Глагол chain принимает список типов столбцов в качестве входных данных и получает герунду, подходящую для использования левого аргумента для ;. (или аналогичного оператора).

Таким образом:

   1 (chain columnTypes);.1  columnify matrix
+---+-----+---------+
|ABC|DEFGH|0j23 0j45|
|FOO|BAR  |         |
+---+-----+---------+

Или, если вам действительно нужна таблица ячеек в штучной упаковке NxM, примените вырезку «под» columnify:

   1 (chain columnTypes);.1&.columnify matrix
+-----+-----+
|ABC  |FOO  |
+-----+-----+
|DEFGH|BAR  |
+-----+-----+
|0j23 |0j45 |
+-----+-----+

Но обратите внимание гораздо более уместно в контексте J сохранять таблицу в виде списка однородных столбцов как для производительности, так и для обозначения.

J лучше всего работает при обработке массивов "in toto"; Практическое правило гласит, что примитивное или пользовательское имя должно видеть как можно больше данных в каждом приложении. В этом главное преимущество этого подхода "columificaton": если вы сохраняете ваши данные в виде списка однородных столбцов, это будет быстрее и проще манипулировать позже.

Однако, если ваш сценарий использования действительно требует, чтобы вы хранили данные в виде таблицы NxM в виде ячеек в штучной упаковке, то преобразование данных в обычную форму и из столбца является дорогостоящей операцией. В этом случае вам следует придерживаться вашего исходного решения,

   1 chain\"1 matrix

, который (потому что вы спросили) на самом деле работает в той же предпосылке, что и ;. подход. В частности, \ - это еще один из тех примитивных операторов, который принимает аргумент gerund и последовательно применяет каждый глагол (то есть к каждому новому окну данных, циклически).

Фактически 1 chain\"1 matrix разбивает матрицу на строки ("1) и для каждой строки создает движущееся окно шириной 1 (1 f\ matrix), применяя глаголы chain к каждому из этих окон шириной 1 (т.е. f изменяется с каждым окном данных шириной 1 в каждой строке матрицы).

Поскольку движущееся окно 1 строки (вектор ранга 1) - это атомы строки по порядку, а глаголы chain даны в том же порядке, в действительности вы применяете те глаголы к столбцам матрицы, один. атом. в. а. время.

Вкратце: 1 chain\"1 matrix аналогично foo"0 matrix, за исключением изменений foo для каждого атома. И этого следует избегать по той же причине: foo"0 matrix следует вообще избегать: потому что применение функций с малым рангом работает против зерна J, влечет за собой снижение производительности.

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

Другими словами, здесь ;. равно "1, как \ равно "0. Если вы обнаружите, что вся вещь columnify / homogenize слишком длинная или громоздкая (по сравнению с 1 chain\"1 matrix), вы можете импортировать скрипт, предоставленный в [1], который упаковывает эти определения как утилиты многократного использования с расширениями. Смотрите страницу с примерами и инструкциями.

[1] Связанный служебный скрипт:
http://www.jsoftware.com/jwiki/DanBron/Snippets/DOOG

2 голосов
/ 02 августа 2011

Если эти расчеты зависят только от данных внутри отдельных блоков (и, возможно, от глобальных значений), можно использовать Повестку дня с Under Open (иначе каждый).Применение этого метода показано ниже:

   doCells  =: (doNum`doString @. isLiteral)&.>
   isLiteral=: 2 -: 3!:0

   doNum    =: +:   NB. Double
   doString =: toupper

   doCells matrix
┌───┬─────┬──┐
│ABC│DEFGH│46│
├───┼─────┼──┤
│FOO│BAR  │90│
└───┴─────┴──┘

(В этом примере я ввел произвольные значения для doNum и doString, чтобы помочь сделать жизнь понятной.)

Используемая здесь версия isLiteral вполне может быть достаточной, но она потерпит неудачу, если будут задействованы разреженные литеральные или юникодные значения.

Если в вычислениях необходимо задействовать больше матрицы, чем одного блока,не будет ответом на ваш вопрос.Если вычисления должны выполняться по линии, вместо этого решение может включать применение глагола с рангом _1 (т.е. к каждому элементу наивысшей оси.)

0 голосов
/ 03 августа 2011

В результате экспериментов я получаю то, что хочу:

1 chain\"1 matrix

Теперь, чтобы понять это ...

...