Skip to content

Instantly share code, notes, and snippets.

@hcliff
Created February 21, 2013 20:22
Show Gist options
  • Save hcliff/5007872 to your computer and use it in GitHub Desktop.
Save hcliff/5007872 to your computer and use it in GitHub Desktop.
get-in, set-in, update-in, nested group-by for underscore
# Extend underscore
_.mixin
lookupIterator: (v)->
if _.isFunction(v)
return v
return (o)-> o[v]
# Given a object and an array of keys return nested items
# _.getIn({"one" : {"two" {"three" : "hi!"}}}, ['one', 'two'])
# -> {"three" : "hi!"}
getIn : (c, k)->
reducer = (ret, x)->
# If the reducer found no key path previously
# ret is undefined and thus will not have the key x
return ret[x] if _.isObject(ret) and _.has(ret, x)
undefined
_.reduce(k, reducer, c)
# Given an object, an array of keys and a value, set the value
# creating the key path as needed
setIn : (c, k, v)->
reducer = (ret, x)->
ret[x] = {} unless _.has(ret, x)
ret[x]
# Set up the key path by creating objects where needed
o = _.reduce(k.slice(0, -1), reducer, c)
# Assign the actual value to the last key
o[_.last(k)] = v
# apply a function f, to the value found at the keypath k in c
# any extra arguments passed onto f
updateIn : (c, k, f, fa...)->
ov = _.getIn c, k
_.setIn c, k, f(ov, fa...)
c
# Implement a nested groupBy, takes a collection c and a
# array of arguments v
groupBy : (c, v) ->
f = _.lookupIterator(v || _.identity)
grouper = (o, v)->
(if _.isUndefined(o) then (o = []) else o).push v
o
reducer = (ret, x)->
_.updateIn(ret, f(x), grouper, x)
_.reduce(c, reducer, {})
console.time('group');
console.log(_.groupBy(response.rows, function(x){return [x['colour'], x['size']]}));
console.timeEnd('group');
# hella fast
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment