Page 1 of 1

[Ruby] Reduce

PostPosted: Wed Feb 14, 2018 6:50 am
by tulamide
I had to look at an array and get either true or false, depending on any value being greater than 1 or lower than -1.

After some time I came up with this:
Code: Select all
over = a.reduce(false) { |memo, n| n.abs >= 1 ? memo = true : memo }


I think it is the shortest form to get the desired result (but please post even shorter versions!), probably even in high execution speed.

'reduce' is a method of the array class that tries to reduce the array to one value, using a provided block. That block gets populated with a memo and the current value, and you can initialize memo (here: reduce(false) sets memo to false). If you don't, it will be initialized with the first value of the array - not good if you're looking for true or false.

The rest of the code checks if the absolute value is greater or equal 1 (digital clipping occured) and sets memo to true. If not, memo is passed back unaltered.

It would be an improvement if, with similar short code, one could break out of the loop on the first occurence of the condition. So, if you know a trick for that, please share :)

Re: [Ruby] Reduce

PostPosted: Wed Feb 14, 2018 9:13 am
by KG_is_back
If you are searching whether at least one value in array matches certain condition, just use .any? method. It also has the added benefit of terminating the iteration once it finds first match. Its inverse is the .all? method which terminates when it find first false.

Code: Select all
over = a.any? { |n| n.abs>=1 }


.any? method is a logical disjunction (logical OR of all values), it correctly returns false if the array is empty. Similarly .all? method returns true for empty array (vacuous truth).

Alternatively you may use .find or .find_index. They also terminate after they find matching element and return that element or nil if nothing was found respectively. It can be very useful when you need to both check if certain element exists and execute operation on it when it does:
Code: Select all
#turret will automatically attack enemy units in range
if target=@units.find{|unit| unit.enemy_of?(self) and unit.in_range_of?(self)}
attack(target)
end

Re: [Ruby] Reduce

PostPosted: Wed Feb 14, 2018 6:57 pm
by tulamide
Yes! .any? is what I was looking for. I was so focused on doing it with reduce that I ignored all the other fine methods. I think that's what is called mindcuffs. :lol:

Re: [Ruby] Reduce

PostPosted: Wed Feb 14, 2018 7:41 pm
by RJHollins
great stuff Guys.

Understood that you're looking to get things done ... but to see ideas develop into
options/solutions and strategy if helpful to all of us [or just Me].

thx
8-)

Re: [Ruby] Reduce

PostPosted: Wed Feb 14, 2018 11:07 pm
by KG_is_back
tulamide wrote:Yes! .any? is what I was looking for. I was so focused on doing it with reduce that I ignored all the other fine methods. I think that's what is called mindcuffs. :lol:


It's called writing in Ruby... just look at stack overflow. Topics for regular languages deal with "how do I make this work?" followed by responses with specific cryptic algorithms written in even more cryptic syntax. Topics for ruby start with "it works, but how do I make it look pretty?" followed by grammar nazis nitpicking each other's suggestions... :lol:

As for enumerables like arrays in ruby, half the methods are technically just modified versions of ".each" For example .any? is under the hood just this:
Code: Select all
def any?()
if block_given?
self.each{|v| return true if yield(v)}
return false
else
self.each{|v| return true if v}
return false
end
end