When writing iterative code with mutation in ruby, I often find myself following this pattern:
def build_x some_data
x = [] # or x = {}
some_data.each do |data|
x.some_in_place_update! (... data ...)
end
x
end
(x often does not have the same shape as some_data, so a simple map will not do.)
Is there a more idiomatic or better way to write code that follows this pattern?
[edit] A real example:
def to_hierarchy stuff
h = {}
stuff.each do |thing|
path = thing.uri.split("/").drop(4)
sub_h = h
path.each do |segment|
sub_h[segment] ||= {}
sub_h = sub_h[segment]
end
sub_h.merge!(
data: thing.data,
)
end
h
end
This begins with a flat list of things, which have related but distinct uris. It transforms this flat list into a hierarchy, grouping related things that share the same segments of a uri. This follows the pattern I described: initialize h, loop over some data and mutate h along the way, and then spit out h at the end.
[edit2] Another related example
def count_data obj
i = if obj[:data] then 1 else 0
obj.each do |k, v|
i += count_statements v unless :data == k
end
i
end
Your
to_hierarchyexample could be done witheach_with_object:each_with_objectpasses the extra object to the block and returns that object when the iteration is done.If you're more of a traditionalist, you could use
inject:Note the block argument order change and that the block has to return
hso thatinjectcan feed it back into the next block invocation.Your general example could be written as:
or: