Skip to content

Instantly share code, notes, and snippets.

@baweaver
Created August 2, 2022 05:53
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baweaver/f01c3a6f5c009b65600a4d63cdc1cacf to your computer and use it in GitHub Desktop.
Save baweaver/f01c3a6f5c009b65600a4d63cdc1cacf to your computer and use it in GitHub Desktop.
Deep grouping, because I keep doing something like this by hand and it gets hard to keep track of.
module DeepGroup
class Grouping
IDENTITY = -> v { v }
def initialize(state)
@state = state
@groupings = []
@mapping = IDENTITY
end
def group_by(&fn)
@groupings << fn
self
end
def map(&fn)
@mapping = fn
self
end
def reduce(&fn)
@reducing = fn
value
end
def count
@counting = true
value
end
def value
return @state if @groupings.empty?
recurse = -> current_state:, groupings: {
if groupings.empty?
next current_state.size if @counting
next current_state.reduce(&@reducing) if @reducing
next current_state.map(&@mapping)
end
group_fn, *remaining_group_fn = groupings
current_state.group_by(&group_fn).transform_values do |vs|
recurse[current_state: vs, groupings: remaining_group_fn]
end
}
recurse[current_state: @state, groupings: @groupings]
end
end
def self.[](v)
Grouping.new(v)
end
end
require "json"
require "net/http"
todos = URI("https://jsonplaceholder.typicode.com/todos")
.then { Net::HTTP.get(_1) }
.then { JSON.parse(_1) }
DeepGroup[todos]
.group_by { |v| v["userId"] }
.group_by { |v| v["completed"] }
.count
# Returns:
{1=>{false=>9, true=>11},
2=>{false=>12, true=>8},
# ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment