Подтвердить что ты не робот

Как отфильтровать список в J?

В настоящее время я изучаю увлекательный J-язык программирования, но одна вещь, которую я не смог выяснить, - как фильтровать список.

Предположим, что у меня есть произвольный список 3 2 2 7 7 2 9, и я хочу удалить 2s, но оставить все остальное без изменений, то есть мой результат будет 3 7 7 9. Как я это делаю?

4b9b3361

Ответ 1

Короткий ответ

   2 (~: # ]) 3 2 2 7 7 2 9
3 7 7 9


Длинный ответ

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

Монады, диады

Существует два типа глаголов в J: монады и диады. Первые принимают только один параметр, последний принимает два параметра.

Например, передавая единственный аргумент монадическому глаголу #, называемый tally, подсчитывает количество элементов в списке:

   # 3 2 2 7 7 2 9
7

Глагол #, который принимает два аргумента (влево и вправо), называется копией, является двоичным и используется для копирования элементов из правого списка столько раз, сколько указано соответствующими элементами в левом списке ( также может быть единственный элемент в списке):

   0 0 0 3 0 0 0 # 3 2 2 7 7 2 9
7 7 7

вилка

Существует понятие вилки в J, которое представляет собой серию из 3 глаголов, применяемых к их аргументам, двояко или монадически.

Здесь диаграмма вида вилки, которую я использовал в первом фрагменте:

 x (F G H) y

      G
    /   \
   F     H
  / \   / \
 x   y x   y

Он описывает порядок, в котором глаголы применяются к их аргументам. Таким образом, эти приложения выполняются:

   2 ~: 3 2 2 7 7 2 9
1 0 0 1 1 0 1

~: (не равно) является двоичным в этом примере и приводит к списку логических значений, которые истинны, если аргумент не равен 2. Это было приложение F в соответствии с диаграммой.

Следующее приложение H:

   2 ] 3 2 2 7 7 2 9
3 2 2 7 7 2 9

] (identity) может быть монадой или диадой, но всегда возвращает правильный аргумент, переданный в глагол (там есть противоположный глагол, [, который возвращает.. Да, левый аргумент!:)

До сих пор так хорошо. F и H после того, как приложение вернет эти значения соответственно:

1 0 0 1 1 0 1
3 2 2 7 7 2 9

Единственный шаг для выполнения - это глагол G.

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

   1 0 0 1 1 0 1 # 3 2 2 7 7 2 9
3 7 7 9

Мы только что получили список из 2 s.

Ссылка

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

Другими полезными источниками информации являются сайт Jsoftware с их wiki и несколько архивов списков рассылки в интернетах.

Ответ 2

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

   3 2 2 7 7 2 9 -. 2

Это возвращает

3 7 7 9

Более сложный метод - генерация логического и его использование для сжатия вектора - больше APLish.

Чтобы ответить на другой вопрос в очень длинном столбце, чтобы вернуть первый элемент и количество раз, это происходит просто:

      ({. , {. +/ .= ]) 1 4 1 4 2 1 3 5
1 3

Это вилка, использующая "{." чтобы получить первый элемент, "{. +/. =]", чтобы добавить количество раз, когда первый элемент равен каждому элементу, и "," в качестве среднего глагола, чтобы объединить эти две части.

Ответ 3

Также:

   2 ( -. ~ ]) 3 2 2 7 7 2 9
3 7 7 9

Ответ 4

Есть миллион способов сделать это - это беспокоит меня, смутно, что эти вещи не оцениваются строго справа налево, я старый программист APL, и я думаю о вещах, как о праве налево, даже когда они нет.

Если бы это была вещь, которую я собирался ввести в программу, где я хотел вытащить некоторое число, а число было константой, я бы сделал следующее:

(#~ 2&~:)  1 3 2 4 2 5
1 3 4 5 

Я думаю, что это крючок. Правая половина выражения генерирует вектор правды, который не является 2, а затем у октоторпа слева есть свои аргументы, которые меняются местами, так что вектор истины является левым аргументом для копирования, а вектор является правильным аргументом. Я не уверен, что крючок работает быстрее или медленнее, чем вилка с копией аргументов.

  +/3<+/"1(=2&{"1)/:~S:_1{;/5 6$1+i.6

156

Эта вышеприведенная программа отвечает на вопрос: "Для всех возможных комбинаций кубиков Yatzee, сколько из них имеет 4 или 5 совпадающих чисел в одном броске?" Он генерирует все перестановки в коробках, сортирует каждый блок отдельно, распаковывая их как побочный эффект и извлекает столбец 2, сравнивая поле со своим собственным столбцом 2, в единственной успешной вилке или крюке, который мне когда-либо удалось написать. Теория состоит в том, что если число, которое появляется в списке из 5, три или более раз, если вы сортируете список, среднее число будет числом, которое появляется с наибольшей частотой. Я попробовал несколько других крючков и/или вилок, и каждый из них потерпел неудачу, потому что я чего-то не получаю. В любом случае эта таблица истинности сводится к вектору, и теперь мы точно знаем, сколько раз каждая группа из 5 кубиков соответствовала медианному числу. Наконец, это число сравнивается с 3, и подсчитывается количество успешных сравнений (больше 3, то есть 4 или 5).

Эта программа отвечает на вопрос: "Для всех возможных 8-значных чисел, составленных из символов с 1 по 5, с повторением, сколько их делится на 4?

Я знаю, что вам нужно только определить, сколько в течение первых 25 делится на 4 и умножается, но программа работает более или менее мгновенно. В какой-то момент у меня была гораздо более сложная версия этой программы, которая сгенерировала числа в базе 5, чтобы отдельные цифры находились между 0 и 4, добавили 1 к генерируемым таким образом числам, а затем поместили их в базу 10. Это было что-то вроде 1+(8$5)#:i.5^8+/0 = 4 |, (8 $10) #. > {;/8 5 $1 + i.5 78125  Пока у меня есть только глагольные поезда и выбор, у меня нет проблем. Когда я начинаю повторять свой аргумент в глаголе, так что я вынужден использовать вилки и крючки, я начинаю теряться.

Например, здесь я не могу работать.

((1&{~+/)*./\(=1&{))1 1 1 3 2 4 1

Я всегда получаю индексную ошибку.

Точка состоит в том, чтобы выводить два числа, то же самое, что и первое число в списке, второе - то же, что и число раз, когда число повторяется.

Так много работает:

*./\(=1&{)1 1 1 3 2 4 1
1 1 1 0 0 0 0

Я сравниваю первое число с остальной частью списка. Затем я делаю вставку и сжатие - и это дает мне 1, если у меня есть непрерывная строка из 1, как только она разбивает и терпит неудачу, и появляются нули.

Я подумал, что я мог бы добавить еще один набор парнеров, снова получить список из списка и каким-то образом записать эти числа, в конечном итоге идея должна состоять в следующем этапе, когда я применяю обратный вектор к оригиналу список, а затем используйте $: для возврата к рекурсивному приложению того же глагола. Похоже на пример quicksort, который, как я думал, я понял, но, думаю, я этого не делаю.

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