dependientes - ¿Cómo filtrar una lista en J?
filtros anidados tableau (4)
La respuesta corta
2 (~: # ]) 3 2 2 7 7 2 9
3 7 7 9
La respuesta larga
Tengo la respuesta para usted, pero antes debe familiarizarse con algunos detalles. Aquí vamos.
Mónadas, díadas
Hay dos tipos de verbos en J: mónadas y díadas . El primero acepta solo un parámetro, el segundo acepta dos parámetros.
Por ejemplo, pasar un único argumento a un verbo monádico #
, llamado tally , cuenta el número de elementos en la lista:
# 3 2 2 7 7 2 9
7
Un verbo #
, que acepta dos argumentos (izquierdo y derecho), se llama copiar , es diádico y se usa para copiar elementos de la lista de la derecha tantas veces como lo especifiquen los elementos respectivos en la lista de la izquierda (puede haber una única elemento en la lista también):
0 0 0 3 0 0 0 # 3 2 2 7 7 2 9
7 7 7
Tenedor
Hay una noción de bifurcación en J, que es una serie de 3 verbos aplicados a sus argumentos, diádicamente o monádicamente.
Aquí está el diagrama de un tipo de horquilla que usé en el primer fragmento:
x (F G H) y
G
/ /
F H
/ / / /
x y x y
Describe el orden en que se aplican los verbos a sus argumentos. Así se producen estas aplicaciones:
2 ~: 3 2 2 7 7 2 9
1 0 0 1 1 0 1
El ~:
(no igual) es diádico en este ejemplo y da como resultado una lista de valores booleanos que son verdaderos cuando un argumento no es igual a 2
. Esta fue la aplicación F
según diagrama.
La siguiente aplicación es H
:
2 ] 3 2 2 7 7 2 9
3 2 2 7 7 2 9
]
( identidad ) puede ser una mónada o una diada , pero siempre devuelve el argumento correcto pasado a un verbo (hay un verbo opuesto, [
que devuelve ... Sí, el argumento de la izquierda! :)
Hasta ahora tan bueno. F
y H
después de la aplicación devolvieron estos valores en consecuencia:
1 0 0 1 1 0 1
3 2 2 7 7 2 9
El único paso a realizar es la aplicación del verbo G
Como señalé anteriormente, el verbo #
, que es diádico (acepta dos argumentos), nos permite duplicar los elementos del argumento correcto tantas veces como se especifica en las posiciones respectivas en el argumento izquierdo. Por lo tanto:
1 0 0 1 1 0 1 # 3 2 2 7 7 2 9
3 7 7 9
Acabamos de filtrar la lista de 2
s.
Referencia
En estos dos documentos se describen tipos ligeramente diferentes de horquilla , gancho y otras primitivas (incluidas las mencionadas anteriormente):
- Una breve referencia de J (175 KiB)
- Easy-J. Una introducción al lenguaje de programación más notable del mundo (302 KiB)
Otras fuentes de información útiles son el sitio de Jsoftware con su wiki y unos pocos archivos de listas de correo en Internet.
Actualmente estoy aprendiendo el fascinante lenguaje de programación J, pero una cosa que no he podido averiguar es cómo filtrar una lista.
Supongamos que tengo la lista arbitraria 3 2 2 7 7 2 9
y quiero eliminar los 2 pero dejar todo lo demás sin cambios, es decir, mi resultado sería 3 7 7 9
. ¿Cómo diablos hago esto?
Hay un millón de maneras de hacer esto; me molesta, vagamente, que estas cosas no se evalúen estrictamente de derecha a izquierda, soy un viejo programador de APL y pienso en las cosas como de derecha a izquierda incluso cuando no están .
Si fuera algo que iba a incluir en un programa en el que quería sacar un número y el número era una constante, haría lo siguiente:
(#~ 2&~:) 1 3 2 4 2 5
1 3 4 5
Esto es una especie de gancho, creo. La mitad derecha de la expresión genera el vector de verdad con respecto al cual no son 2, y luego el octothorpe de la izquierda tiene sus argumentos intercambiados de modo que el vector de verdad es el argumento de la izquierda para copiar y el vector es el argumento de la derecha. No estoy seguro de que un gancho sea más rápido o más lento que un tenedor con una copia de argumento.
+/3<+/"1(=2&{"1)/:~S:_1{;/5 6$1+i.6
156
Este programa anterior responde a la pregunta: "Para todas las combinaciones posibles de dados Yatzee, ¿cuántos tienen 4 o 5 números coincidentes en una tirada?" Genera todas las permutaciones, en cuadros, clasifica cada cuadro individualmente, desempaquetándolos como efecto secundario, y extrae la columna 2, comparando el cuadro con su propia columna 2, en la única bifurcación o gancho exitoso que he logrado escribir. La teoría es que si hay un número que aparece en una lista de 5, tres o más veces, si ordena la lista, el número central será el número que aparezca con la mayor frecuencia. He intentado una serie de otros ganchos y / o horquillas y todos han fallado porque hay algo que simplemente no entiendo. De todos modos, la tabla de verdad se reduce a un vector, y ahora sabemos exactamente cuántas veces cada grupo de 5 dados coincide con el número mediano. Finalmente, ese número se compara con 3, y se cuenta el número de comparaciones exitosas (más de 3, es decir, 4 o 5).
Este programa responde a la pregunta: "Para todos los números posibles de 8 dígitos hechos de los símbolos del 1 al 5, con repetición, ¿cuántos son divisibles por 4?"
Sé que solo necesitas determinar cuántos dentro de los primeros 25 son divisibles por 4 y se multiplican, pero el programa se ejecuta más o menos instantáneamente. En un momento tuve una versión mucho más compleja de este programa que generaba los números en la base 5, de modo que los dígitos individuales estaban entre 0 y 4, agregaba 1 a los números así generados y luego los ponía en la base 10. Eso era algo así como 1+(8$5)#:i.5^8
+ / 0 = 4 |, (8 $ 10) #. > {; / 8 5 $ 1 + i.5 78125 Mientras tenga únicamente selección y selección de verbos, no tengo ningún problema. Cuando comienzo a tener que repetir mi argumento dentro del verbo para forzarme a usar las horquillas y los ganchos, comienzo a perderse.
Por ejemplo, aquí hay algo que no puedo ponerme a trabajar.
((1&{~+/)*.//(=1&{))1 1 1 3 2 4 1
Siempre me sale un error de índice.
El punto es dar salida a dos números, uno que sea el mismo que el primer número en la lista, el segundo que sea el mismo que el número de veces que se repite ese número.
Así que esto funciona mucho:
*.//(=1&{)1 1 1 3 2 4 1
1 1 1 0 0 0 0
Yo comparo el primer número con el resto de la lista. Luego hago una inserción de y una compresión, y esto me da un 1 siempre que tenga una cadena ininterrumpida de 1, una vez que se rompe y falla, y aparecen los ceros.
Pensé que luego podría agregar otro conjunto de paréntesis, obtener el elemento principal de la lista nuevamente y, de alguna manera, registrar esos números, la idea final sería tener otra etapa en la que aplique el inverso del vector a la lista original, y luego use $: para volver para una aplicación recursiva del mismo verbo. Algo así como el ejemplo de orden rápido, que pensé que entendía, pero supongo que no.
Pero ni siquiera puedo acercarme. Preguntaré esto como una pregunta separada para que las personas obtengan el crédito adecuado para responder.
Solo para asegurarnos de que esté claro, la forma directa, para responder a la pregunta original, es esta:
3 2 2 7 7 2 9 -. 2
Esto devuelve
3 7 7 9
El método más elaborado, generar el booleano y usarlo para comprimir el vector, es más efectivo.
Para responder a la otra pregunta en el post muy largo, para devolver el primer elemento y el número de veces que ocurre, es simplemente esto:
({. , {. +/ .= ]) 1 4 1 4 2 1 3 5
1 3
Esta es una bifurcación usando "{." para obtener el primer elemento, "{. + /. =]" para sumar el número de veces que el primer elemento es igual a cada elemento, y "," como el verbo del medio para concatenar estas dos partes.
También:
2 ( -. ~ ]) 3 2 2 7 7 2 9
3 7 7 9