-
Notifications
You must be signed in to change notification settings - Fork 44
Is it possible to write a transducer to perform zip? #11
Comments
It is possible, in fact Clojure/ClojureScript don't even bother with |
I'm intrigued that Clojure/ClojureScript provide this via map. Could you elaborate how this is achieved? |
In Clojure/ClojureScript I'll ask around to see if adding |
OK great, thanks for looking into this. |
+1 |
This can be done easily with reduce: [['a', 'b', 'c'][1, 2, 3]].reduce(function(result, item){
return item.map(function(elem, index){
return [].concat(result[index]).concat(elem)
}
}, []) I wasn't quite sure how to write that with transducers right now |
Can be done like this... import tr from 'transducers-js';
function zip() {
return xf => Zip(xf);
}
const sub = Symbol('sub');
function Zip(xf) {
return {
['@@transducer/init']() {
const result = { [sub]: [] };
// if init is not implemented in wrapped, ignore
try {
result.wrapped = xf['@@transducer/init']();
}
catch(err) { }
return result;
},
['@@transducer/result'](result) {
if(result[sub] == null || result[sub].length === 0) {
return result.wrapped || result;
}
const wrappedResult = result[sub][0].reduce((acc, input, i)=>
xf['@@transducer/step'](acc, result[sub].map((a)=>a[i]))
, result.wrapped);
return xf['@@transducer/result'](wrappedResult);
},
['@@transducer/step'](result, input) {
if(result[sub] == null) {
// "into" - init not called
const acc = this['@@transducer/init']();
// pass the evil on to the wrapped accumulator
acc.wrapped = result;
result = acc;
}
result[sub].push(input);
return result;
}
};
}
console.log(tr.into([], zip(), [[1,2,3], [4,5,6]]));
// output: [ [ 1, 4 ], [ 2, 5 ], [ 3, 6 ] ] GrumbleIMHO, the protocol should always call Perhaps I am missing something? Instead of putting state into the accumulator, I could store it in the transformer itself (or also in the closure that creates the transformer object). But why chain the accumulators at all if they aren't meant to store state? The question would be -- what would be expected of the code: const zip0 = zip();
console.log(tr.into([], zip0, [[1,2,3], [4,5,6]]));
console.log(tr.into([], zip0, [[1,2,3], [4,5,6]])); Presumably this is wrong (?) -- into() expects something stateless and then (should) set up? |
Hi @shaunc Your zip transducer doesn't work well: const input = [[1,2,3], [4,5,6]]
const transducer = tr.comp(
zip(),
tr.take(2)
)
const output = tr.into([], transducer, input)
console.log(output); /* {
'@@transducer/reduced': true,
'@@transducer/value': [ [ 1, 4 ], [ 2, 5 ] ]
} */ Cheers! |
I wasn't sure where best to ask this question. Please point me in the right direction if this is not the best place.
I was wondering if it possible to create a transducer that acted like rx's zip? For example say I had a collection of collections
[[a, b, c][1, 2, 3]]
I would like it to be transformed into[[a,1], [b,2], [c,3]]
.Taking this a step further it would be great to be able to write it in a more reusable way, for example a combinator transducer that takes a function that will be called with the nth element of each nested collection:
The text was updated successfully, but these errors were encountered: