Atualização de 2016:
Aqui está uma versão mais ecológica do Ecmascript 6:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
Ilustração equiv. para Python { zip(*args)
}:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(e o FizzyTea salienta que o ES6 tem sintaxe de argumento variada, portanto a seguinte definição de função funcionará como python, mas veja abaixo o aviso de isenção de responsabilidade ... isso não será o seu próprio inverso, portanto zip(zip(x))
não será igual x
; embora, como Matt Kramer aponte zip(...zip(...x))==x
(como em python comum zip(*zip(*x))==x
))
Definição alternativa equiv. para Python { zip
}:
> zip = (...rows) => [...rows[0]].map((_,c) => rows.map(row => row[c]))
> zip( ['row0col0', 'row0col1', 'row0col2'] ,
['row1col0', 'row1col1', 'row1col2'] );
// note zip(row0,row1), not zip(matrix)
same answer as above
(Observe que a ...
sintaxe pode ter problemas de desempenho no momento e possivelmente no futuro; portanto, se você usar a segunda resposta com argumentos variados, poderá testá-la com perfeição.)
Aqui está um oneliner:
function zip(arrays) {
return arrays[0].map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
// > zip([[1,2],[11,22],[111,222]])
// [[1,11,111],[2,22,222]]]
// If you believe the following is a valid return value:
// > zip([])
// []
// then you can special-case it, or just do
// return arrays.length==0 ? [] : arrays[0].map(...)
O exposto acima pressupõe que as matrizes sejam do mesmo tamanho, como deveriam ser. Também assume que você passa em um único argumento da lista de listas, diferente da versão do Python, onde a lista de argumentos é variável. Se você deseja todos esses "recursos", veja abaixo. São necessárias apenas duas linhas de código extras.
A seguir, imitaremos o zip
comportamento do Python em casos extremos onde as matrizes não são do mesmo tamanho, fingindo silenciosamente que as partes mais longas das matrizes não existem:
function zip() {
var args = [].slice.call(arguments);
var shortest = args.length==0 ? [] : args.reduce(function(a,b){
return a.length<b.length ? a : b
});
return shortest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222]]]
// > zip()
// []
Isso imitará o itertools.zip_longest
comportamento do Python , inserindo undefined
onde as matrizes não estão definidas:
function zip() {
var args = [].slice.call(arguments);
var longest = args.reduce(function(a,b){
return a.length>b.length ? a : b
}, []);
return longest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222],[null,null,333]]
// > zip()
// []
Se você usar essas duas últimas versões (variadic, também conhecida como versões com vários argumentos), o zip não será mais o seu próprio inverso. Para imitar o zip(*[...])
idioma do Python, você precisará fazer isso zip.apply(this, [...])
quando quiser inverter a função zip ou se desejar ter um número variável de listas como entrada.
adendo :
Para tornar esse manipulador iterável (por exemplo, em Python, você pode usar zip
em strings, intervalos, objetos de mapa etc.), você pode definir o seguinte:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
No entanto, se você escrever zip
da seguinte maneira , mesmo isso não será necessário:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
Demo:
> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(Ou você pode usar uma range(...)
função Python-estilo, se você escreveu um já. Eventualmente, você será capaz de usar compreensões de matriz ECMAScript ou geradores).