Created
August 2, 2022 05:53
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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