Skip to content

Instantly share code, notes, and snippets.

@a-laughlin
Last active October 21, 2016 02:20
Show Gist options
  • Select an option

  • Save a-laughlin/401a225fb08968487237abaeef6ec77b to your computer and use it in GitHub Desktop.

Select an option

Save a-laughlin/401a225fb08968487237abaeef6ec77b to your computer and use it in GitHub Desktop.
lodash reduce experiments for composing values

###Results from running function at bottom in console: ###Lodash 4.10 reduce vs vanilla reduce

_.reduce(['a','b','c'],(last,next)=>(last+next)) vs ['a','b','c'].reduce((last,next)=>(last+next))
// abc vs abc
_.reduce(['a','b','c'],(last,next)=>(last+next),undefined) vs ['a','b','c'].reduce((last,next)=>(last+next),undefined)
// undefinedabc vs undefinedabc
_.reduce(['b','c'],(last,next)=>(last+next),'a') vs ['b','c'].reduce((last,next)=>(last+next),'a')
// abc vs abc
_.reduce(['a'],(last,next)=>(last+next),undefined) vs ['a'].reduce((last,next)=>(last+next),undefined)
// undefineda vs undefineda
_.reduce(['a'],(last,next)=>(last+next)) vs ['a'].reduce((last,next)=>(last+next))
// a vs a
_.reduce([],(last,next)=>(last+next),'a') vs [].reduce((last,next)=>(last+next),'a')
// a vs a
_.reduce([(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'],(last,next)=>next(last)) vs [(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'].reduce((last,next)=>next(last))
// (l)=>l+' ' + 'a' b c vs (l)=>l+' ' + 'a' b c

###Lodash only

_.reduce([(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'],(last,next)=>next(typeof last === 'function'? last() :last))
// undefined a b c
_.reduceRight([(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'],(last,next)=>next(typeof last === 'function'? last() :last))
// undefined c b a
_.flow([(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'],(last,next)=>next(typeof last === 'function'? last() :last))('z')
// TypeError: next is not a function(…)
_.flowRight([(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c'],(last,next)=>next(typeof last === 'function'? last() :last))('z')
// TypeError: next is not a function(…)
_.flow([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(last,next)=>next(typeof last === 'function'? last() :last))('z')
// TypeError: next is not a function(…)
_.flowRight([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(last,next)=>next(typeof last === 'function'? last() :last))('z')
// TypeError: next is not a function(…)
_.flow([(l)=>l+' '+'a',(l)=>l+' '+'b',(l)=>l+' '+'c'],(v)=>v)('z')
// z a b c
_.flowRight([(l)=>l+' '+'a',(l)=>l+' '+'b',(l)=>l+' '+'c'],(v)=>v)('z')
// z c b a
_.flow([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(v)=>v)('z')
// z undefined a undefined b undefined c
_.flowRight([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(v)=>v)('z')
// z undefined c undefined b undefined a
_.flow([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(v,v2)=>v+' '+v2)('z')
// z undefined a undefined b undefined c undefined
_.flowRight([(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c'],(v,v2)=>v+' '+v2)('z')
// z undefined undefined c undefined b undefined a

###Console Fn

[
  [`['a','b','c']`,`(last,next)=>(last+next)`, `_.reduce(arr,runner) vs arr.reduce(runner)`],
  [`['a','b','c']`,`(last,next)=>(last+next)`, `_.reduce(arr,runner,undefined) vs arr.reduce(runner,undefined)`],
  [`['b','c']`,`(last,next)=>(last+next)`, `_.reduce(arr,runner,'a') vs arr.reduce(runner,'a')`],
  [`['a']`,`(last,next)=>(last+next)`, `_.reduce(arr,runner,undefined) vs arr.reduce(runner,undefined)`],
  [`['a']`,`(last,next)=>(last+next)`, `_.reduce(arr,runner) vs arr.reduce(runner)`],
  [`[]`,`(last,next)=>(last+next)`, `_.reduce(arr,runner,'a') vs arr.reduce(runner,'a')`],
  [`[(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c']`, `(last,next)=>next(last)`, `_.reduce(arr,runner) vs arr.reduce(runner)`],
  [`[(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.reduce(arr,runner)`],
  [`[(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.reduceRight(arr,runner)`],
  [`[(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.flow(arr,runner)('z')`],
  [`[(l)=>l+' ' + 'a',(l)=>l+' ' + 'b',(l)=>l+' ' + 'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.flowRight(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.flow(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(last,next)=>next(typeof last === 'function'? last() :last)`, `_.flowRight(arr,runner)('z')`],
  [`[(l)=>l+' '+'a',(l)=>l+' '+'b',(l)=>l+' '+'c']`, `(v)=>v`, `_.flow(arr,runner)('z')`],
  [`[(l)=>l+' '+'a',(l)=>l+' '+'b',(l)=>l+' '+'c']`, `(v)=>v`, `_.flowRight(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(v)=>v`, `_.flow(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(v)=>v`, `_.flowRight(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(v,v2)=>v+' '+v2`, `_.flow(arr,runner)('z')`],
  [`[(l,m)=>l+' '+m+' '+'a',(l,m)=>l+' '+m+' '+'b',(l,m)=>l+' '+m+' '+'c']`, `(v,v2)=>v+' '+v2`, `_.flowRight(arr,runner)('z')`],
].forEach((strings)=>{
  let [arr,runner,fns] = strings;
  let toLog = fns.replace(/arr/g,arr).replace(/runner/g,runner);
  let toEval = toLog.split(' vs ');
  console.warn(toLog);
  try{
    console.log(toEval.map(eval).join(' vs '))
  } catch(e){
    console.log(e.valueOf());
  }
});

Bunch of additional reducer experiments

(function(){
function foo(a,b){return ['foo',a,b].join(' ')}
function bar(a,b){return ['bar',a,b].join(' ')}
function baz(a,b){return ['baz',a,b].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduceRight(vals.slice(0,-1),(last,next)=>{
    return next(last,..._.slice(arguments,1));
  },vals[vals.length -1](...arguments));
}
return bop(1,2,3,4,5,6);
}());


(function(){
function foo(a,b){return ['foo',a,b].join(' ')}
function bar(a,b){return ['bar',a,b].join(' ')}
function baz(a,b){return ['baz',a,b].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduce(vals.slice(1),(last,next)=>{
    return next(last,..._.slice(arguments,1));
  },vals[0](...arguments));
}
return bop(1,2,3,4,5,6);
}());
"baz bar foo 1 2 2 2"
// breakdown:
// 
//         foo a  b
//     bar     a    b
// baz         a      b
//         foo  a   2
//     bar    last    2
// baz       last       2


(function(){
function foo(a,b){return ()=>['foo', a].join(' ')}
function bar(a,b){return ()=>['bar', a].join(' ')}
function baz(a,b){return ()=>['baz', a].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduce(vals.slice(1),(last,next)=>{
    return next(last(...arguments),..._.slice(arguments,1));
  },vals[0](...arguments))();
}
return bop(1,2,3,4,5,6);
}());
// expected: "foo bar foo baz foo 1 1 1"
// actual: "baz bar foo 1"
// 
// baz
//     bar
//          foo 1
// 
//                   
(function(){
function foo(a,b){return ()=>['foo', ...arguments].join(' ')}
function bar(a,b){return ()=>['bar', ...arguments].join(' ')}
function baz(a,b){return ()=>['baz', ...arguments].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduce(vals.slice(1),(last,next)=>{
    return next(last(...arguments),..._.slice(arguments,1));
  },vals[0](...arguments))();
}
return bop(1,2,3,4,5,6);
}());
//          foo 1 2 3 4 5 6
//      bar                 2 3 4 5 6
// "baz                               2 3 4 5 6"
// 



(function(){
function foo(a,b){return ()=>['foo', ...arguments].join(' ')}
function bar(a,b){return ()=>['bar', ...arguments].join(' ')}
function baz(a,b){return ()=>['baz', ...arguments].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduce(vals.slice(1),(last,next)=>{
    return last(next(...arguments)(),..._.slice(arguments,1));
  },vals[0]);
}
return bop(1,2,3,4,5,6);
}());
// "foo bar 1 2 3 4 5 6 2 3 4 5 6"
// 

(function(){
function foo(a,b){return (next)=>['foo', next, ...arguments].join(' ')}
function bar(a,b){return (next)=>['bar', next, ...arguments].join(' ')}
function baz(a,b){return (next)=>['baz', next, ...arguments].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduce(vals.slice(1),(last,next)=>{
    return last(next(...arguments)())
  },vals[0]);
}
return bop(1,2,3,4,5,6);
}());

// "foo baz  1 2 3 4 5 6 bar  1 2 3 4 5 6"
// 
// 
(function(){
function foo(a,b){return (next)=>['foo', next, ...arguments].join(' ')}
function bar(a,b){return (next)=>['bar', next, ...arguments].join(' ')}
function baz(a,b){return (next)=>['baz', next, ...arguments].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduceRight(vals.slice(1),(last,next)=>{
    return last(next(...arguments)(...arguments))
  },vals[0]);
}
return bop(1,2,3,4,5,6);
}());
// "foo bar 1 1 2 3 4 5 6 baz 1 1 2 3 4 5 6"
// 
// 
(function(){
function foo(a,b){return (next)=>['foo', next, ...arguments].join(' ')}
function bar(a,b){return (next)=>['bar', next, ...arguments].join(' ')}
function baz(a,b){return (next)=>['baz', next, ...arguments].join(' ')}
function bop(){
  var vals = [foo,bar,baz];
  return _.reduceRight(vals.slice(1),(last,next)=>{
    return last(next(...arguments)(...arguments),...arguments)
  },vals[0]);
}
return bop(1,2,3,4,5,6);
}());
// "foo bar 1 1 2 3 4 5 6 baz 1 1 2 3 4 5 6 1 2 3 4 5 6"
// this I don't get... why is it an error to append () to the last() call?


var fooOuterCalled = 0; 
var fooInnerCalled = 0; 
(function(){
  function foo(a,b){
    ++fooOuterCalled;
    debugger;
    return (next)=>++fooInnerCalled && ['foo', next, ...arguments].join(' ')
  }
  function bar(a,b){
    return (next)=>['bar', next, ...arguments].join(' ')
  }
  function baz(a,b){
    return (next)=>['baz', next, ...arguments].join(' ')
  }
  function bop(){
    var vals = [foo,bar,baz];
    return _.reduceRight(vals.slice(1),(last,next)=>{
      return last(next(...arguments)(...arguments),...arguments)
    },vals[0]);
  }
  return bop(1,2,3,4,5,6);
}());
console.log(`fooOuterCalled`, fooOuterCalled);
console.log(`fooInnerCalled`, fooInnerCalled);

// Ahhhhh... fooOuter gets called, fooInner becomes last, then executes on the next loop
// trying to call it on the first loop returns the value, so we can't call last.
// That should mean I can prepend Foo's numbers ahead of next.
// 

(function(){
  function foo(a,b){return (a, b)=>['foo', a, b, ...arguments].join(' ')}
  function bar(a,b){return (a, b)=>['bar', a, b, ...arguments].join(' ')}
  function baz(a,b){return (a, b)=>['baz', a, b, ...arguments].join(' ')}
  function bop(){
    var vals = [foo,bar,baz];
    return _.reduceRight(vals.slice(1),(last,next)=>{
      return last(...arguments,next(...arguments)(...arguments))
    },vals[0]);
  }
  return bop(1,2,3,4,5,6);
}());
// "foo 1 2 1 2 3 4 5 6 baz 1 2 1 2 3 4 5 6"


(function(){
  function foo(a,b){return (a, b)=>['foo', a, b, ...arguments].join(' ')}
  function bar(a,b){return (a, b)=>['bar', a, b, ...arguments].join(' ')}
  function baz(a,b){return (a, b)=>['baz', a, b, ...arguments].join(' ')}
  function bop(){
    var vals = [foo,bar,baz];
    return _.reduceRight(vals.slice(1),(last,next)=>{
      return last(...arguments,...next(...arguments)(...arguments))
    },vals[0]);
  }
  return bop(1,2,3,4,5,6);
}());
// "foo 1 2 1 2 3 4 5 6 b a z   1   2   1   2   3   4   5   6"

// additional experiments}...
(function(){
  function foo(a,b){return (a, b)=>a(b);}
  function bar(a,b){return (a, b)=>a(b);}
  function baz(a,b){return (a, b)=>a(b);}
  function bop(){
    var vals = [foo,bar,baz];
    return _.reduceRight(vals.slice(1),(last,next)=>{
      console.log(`last`, last);
      return last[0](next,...arguments);
    },[vals[0]]);
  }
  return bop(1,2,3,4,5,6);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment