Transponer lista de listas sin un bucle forMe gustaría tener un método para transponer una lista de listas sin utilizar un bucle for. Es decir, alguna función (llámela "Listtranspose", por ejemplo) que invierte las "filas" y "columnas" de una lista de listas, como esta:
listlist = {{"cat", "dog", "mouse"}, {"meow", "bark", "squeak"}};
tranlist = Listtranspose(listlist);
Show(tranlist);
/*Result:
{{"cat", "meow"}, {"dog", "bark"}, {"mouse", "squeak}}
Una implementación alternativa podría ser algo como:
listlist = {{"cat", "dog", "mouse"}, {"meow", "bark", "squeak"}};
nr = NItems(listlist);
col1 = listlist[1::nr][1];
col2 = listlist[1::nr][2];
col3 = listlist[1::nr][3];
translist = EvalList({col1, col2, col3});
Me gusta más la última implementación, ya que es posible que solo necesite transponer un subconjunto de "columnas", no la lista completa.
Por supuesto, esto se puede hacer usando un bucle For, pero la razón para solicitarlo es que los bucles For pueden ser lentos. Trabajo con grandes bloques de texto y creo que esto me ayudaría a acelerar mucho las cosas.
Crédito a @vince_faller por preguntar esto originalmente.Transponer lista de listas sin un bucle for
Automatización y secuencias de comandosRe: Transponer lista de listas sin bucle forPensando en esto un poco más.Todavía no puedo superar el bucle for, pero pensé en escribir esto en caso de que ayude a alguien.
// make a blank data table with the right shape
dt = As Table(J(nr, nc, .), <<PRIVATE></PRIVATE>
Re: Transponer lista de listas sin bucle for@Craige_Hales Gracias por la tremenda idea Craig. Estoy de acuerdo, hice una prueba de velocidad del método de bucle for versus asignación paralela, y la asignación paralela fue mucho más lenta. Mi matriz de lista era 718r x 14182c, por lo que >10 millones de elementos. Ejecuté el script durante aproximadamente 10 minutos y la operación no se completó. Esto parece ser un poco más lento de lo que predicen los datos anteriores, pero hay demasiadas variables para considerar (por ejemplo, sistema informático, proporción de columnas y filas). El bucle For es mucho más rápido con ~10,1 s para la misma tabla.
Aunque sigue siendo más lento de lo que me gustaría. Sería fantástico tener una función JMP que pueda hacer esto internamente.
Re: Transponer lista de listas sin bucle forPero, después de algunas pruebas, creo que un bucle anidado simple será más rápido que cualquier otro enfoque basado en JSL.
result = {};
for( c = 1, c <= nc, c += 1,
thisrow = {}; // build a row from a column
for( r = 1, r <= nr, r += 1,
thisrow[r] = testList[r][c];
);
result[c] = thisrow;
);@DonMcCormack - ¡Desafío!
The blue-line for-loop is consistently better. The purple JSON-table might overtake it, but I'm running out of memory. The parallel-assign trick begins to fail for large numbers.The blue-line for-loop is consistently better. The purple JSON-table might overtake it, but I'm running out of memory. The parallel-assign trick begins to fail for large numbers.El bucle for de línea azul es consistentemente mejor. La tabla JSON violeta podría superarlo, pero me estoy quedando sin memoria. El truco de la asignación paralela comienza a fallar en el caso de números grandes.
La asignación paralela probablemente esté bloqueando subprocesos entre sí, todo el tiempo. Al principio supera a la tabla de datos json debido a los diferentes gastos generales entre los dos.
Re: Transponer lista de listas sin bucle forSí, sería bueno tener más funciones de manipulación de listas. No se me ocurre una manera agradable o rápida, pero después de jugar un poco se me ocurrió esto. Necesita JMP 15, falla en 14.
list = {{"lion", "tiger", "puma"}, {"lamp", "torch", "pharos"}, {"lark", "toucan", "pigeon"}, {"lawn", "terrace", "patio"}};
jlist = As JSON Expr( list );
dt1 = JSON To Data Table( jlist, invisible(1) );
dt1 << New Column( "row", numeric, setvalues( 1 + Floor( (0 :: (N Rows( dt1 ) - 1)) / N Items( list[1] ) ) ) );
dt2 = dt1 << Split( Split By( :row ), Split( column(dt1,1) ), Sort by Column Property, invisible(1) );
Close( dt1, nosave );
transposed = dt2[0, 0];
Close( dt2, nosave );
Show( list, transposed );lista = {{"león", "tigre", "puma"}, {"lámpara", "antorcha", "pharos"}, {"alondra", "tucán", "paloma"}, {"césped", "terraza", "patio"}};
transpuesto = {{"león", "lámpara", "alondra", "césped"}, {"tigre", "antorcha", "tucán", "terraza"}, {"puma", " faros ", "paloma", "patio"}};
Muestra las tablas intermedias para ver qué está haciendo. Una solución real debería ocuparse de filas de longitud desigual.
Re: Transponer lista de listas sin bucle for@Craige_Hales Escribí una gran explicación que uso regularmente.Solución de problemas de subprocesos múltiples mediante Parallel Assign
Re: Transponer lista de listas sin bucle for@vince_faller
Mente == soplado.
Nunca antes había oído hablar de la función Parallel Assign. Probé esto y sí, funciona. Aunque estoy trabajando con cadenas de caracteres y esto es técnicamente una función matricial, de alguna manera no le importa. Será interesante jugar con esto y ver si es más rápido que un bucle for. Intentaré actualizar aquí una vez que lo sepa.
¡Gracias por la idea!
Re: Transponer lista de listas sin bucle forLo juro de arriba abajo que vi a alguien hacer algo parecido a
{"cat", "dog", "mouse", "meow", "bark", "squeak"}[[1 1, 1 1]]
// and had it return
{{"cat", "cat"}, {"cat", "cat"}}
durante una charla en Discovery, pero nunca pude recrearlo.¿Podría haber sido todo un sueño?
Si no recuerdo mal, de alguna manera dieron forma a una nueva lista a partir de una lista plana en una línea como esa.Probablemente no lo recuerdo bien.
Dicho esto, probablemente puedas realizar una asignación en paralelo muy rápido.
names default to here(1);
listlist = {{"cat", "dog", "mouse"}, {"meow", "bark", "squeak"}};
m = J(nc, nr, -1);
::trans_list = Aslist(m);
Parallel Assign({l = listlist},
m[a, b] = (
::trans_list[a][b] = l[b][a];
)
);
show(::trans_list);