When there is a situation where I want to accumulate a value I see myself using inject/reduce with a conditional statement. E.g., when I want to add 1 to a value each time an element in a list has a certain value I do something like this:
puts names.reduce(0) {|acc, name| triangles.include?(name.points) ? acc+=1 : acc}
Here names is an array of names, triangles is a list of the first 30 triangle integers (1/2n(n+1))
and points is a method added to class String
which calculates the integers value of each character in the name and adds them. So the point is to check how many names in the list are triangle values when you calculate the points in that way.
The issue I have is with the conditional area ([conditional] ? acc+=1 : acc
). You can also rewrite the method as:
result = 0
names.each {|name| result +=1 if triangles.include?(name.points)}
puts result
But this method uses three lines and has to initialize the variable at first.
Is there a better way to keep track of the amount (e.g., result, or the acc
in the inject/reduce) that does not use the conditional operator (?
) or costs three lines of code?
triangles
is an array? better a structure with O(1) inclusion predicates (i.e. a set). \$\endgroup\$triangles
is an array of integers, yes. @tokland what do you mean with a O(1) inclusion predicate/set and how would I implement this? \$\endgroup\$array.include?(item)
is O(n) on arrays but O(1) on set.set = array.to_set
and then use it for inclussion tests. \$\endgroup\$