PowerShell: functional: reduce: How to initialize the reduce accumulator? - ruby

I want to use the functional "reduce" function to calculate things, such as the factorial of a number. e.g. The factorial of 5 is 5x4x3x2x1 = 120. In Ruby I can do it with something like:
# factorial1.rb
(1..5).reduce{|accumulator,element| accumulator*element}
In PowerShell I would do something like:
# factorial.ps
# ------ Install this library before using the "reduce" function
# Install-Module -Name functional
1..5 | reduce {$a*$b}
In both languages, the answer is 120, and the accumulator is assumed to be an integer, with an
initial value of the first element in the range.
If I redefined the factorial to have an initial value of 10, in Ruby I
would code it as
# factorial2.rb
# (1..5).reduce {|accumulator,element| accumulator*element} #uninitialized accumulator
(1..5).reduce(10){|accumulator,element| accumulator*element}
This yields the expected answer of 1200.
QUESTION 1: How does one initialize a "reduce" accumulator in PowerShell?
In the next scenario, I want to generate a list of factorials. If
I were to code it in Ruby, I could initialize the reduce accumulator
with [1] (because 0! is 1), resulting in the following code:
# factorial.rb
# (1..5).reduce {|accumulator,element| accumulator*element} #uninitialized accumulator
(1..5).reduce([1]){|accumulator,element| accumulator << accumulator[-1]*element}
The output looks something like
=> [1, 1, 2, 6, 24, 120]
QUESTION 2: How does one use an expandable array to initialize the accumulator for the
PowerShell "reduce" function of the "functional" module?

These questions are specific to the third party functional module that you downloaded assumely from the PS Gallery. Being at under 300 downloads and only a couple commits on GitHub this appears to be a very small project.
I took a quick look at the code base and didn't see a way to do what you were looking for, but functional programming isn't my forte. Maybe you can find what you are looking for in the code base and I just missed it.
Otherwise finding a different third-party module or filling a feature request might be other avenues to pursue.

Using the same reduce-object cmdlet from the functional module, getting a list of accumulated values of a factorial would be:
# 1..10 | %{ 1..$_ | Reduce-Object { $a * $b } }
1
2
6
24
120
720
5040
40320
362880
3628800

Related

Correct semantic usage of map

I am trying to understand what is a semantically right way to use map. As map can behave the same way as each, you could modify the array any way you like. But I've been told by my colleague that after map is applied, array should have
the same order and the same size.
For example, that would mean using the map to return an updated array won't be the right way to use map:
array = [1,2,3,4]
array.map{|num| num unless num == 2 || num == 4}.compact
I've been using map and other Enumerator methods for ages and never thought about this too much. Would appreciate advice from experienced Ruby Developers.
In Computer Science, map according to Wikipedia:
In many programming languages, map is the name of a higher-order
function that applies a given function to each element of a list,
returning a list of results in the same order
This statement implies the returned value of map should be of the same length (because we're applying the function to each element). And the returned-elements are to be in the same order. So when you use map, this is what the reader expects.
How not to use map
arr.map {|i| arr.pop } #=> [3, 2]
This clearly betrays the intention of map since we have a different number of elements returned and they are not even in the original order of application. So don't use map like this. See "How to use ruby's value_at to get subhashes in a hash" and subsequent comments for further clarification and thanks to #meager for originally pointing this out to me.
Meditate on this:
array = [1,2,3,4]
array.map{|num| num unless num == 2 || num == 4} # => [1, nil, 3, nil]
.compact # => [1, 3]
The intermediate value is an array of the same size, however it contains undesirable values, forcing the use of compact. The fallout of this is CPU time is wasted generating the nil values, then deleting them. In addition, memory is being wasted generating another array that is the same size when it shouldn't be. Imagine the CPU and memory cost in a loop that is processing thousands of elements in an array.
Instead, using the right tool cleans up the code and avoids wasting CPU or memory:
array.reject { |num| num == 2 || num == 4 } # => [1, 3]
I've been using map and other Enumerator methods for ages and never thought about this too much.
I'd recommend thinking about it. It's the little things like this that can make or break code or a system, and everything we do when programming needs to be done deliberately, avoiding all negative side-effects we can foresee.

Generate a random number in ruby with some conditions

I have no idea of how to proceed, I've been learning ruby for just one week. I thought I'd create an array filled by an external source, such as a database and forbid these elements inside to be picked up by the script. Is it possible? I just want to have a general idea of how creating such script.
Do you mean some thing like this?
forbidden_numbers = [ 5 , 6 , 3 , 4]
new_number = loop do
tmp_number = rand 1_000_000
break tmp_number unless forbidden_numbers.include?(tmp_number)
end
puts new_number
In general, you have two choices:
Remove the ineligible elements, then choose one at random:
arr.reject {...}.sample
Choose an element at random. If it is disallowed, repeat, continuing until a valid element is found:
until (n=arr.sample) && ok?(n) end
n
Without additional information we cannot say which approach is best in this case.

How to populate an array with incrementally increasing values Ruby

I'm attempting to solve http://projecteuler.net/problem=1.
I want to create a method which takes in an integer and then creates an array of all the integers preceding it and the integer itself as values within the array.
Below is what I have so far. Code doesn't work.
def make_array(num)
numbers = Array.new num
count = 1
numbers.each do |number|
numbers << number = count
count = count + 1
end
return numbers
end
make_array(10)
(1..num).to_a is all you need to do in Ruby.
1..num will create a Range object with start at 1 and end at whatever value num is. Range objects have to_a method to blow them up into real Arrays by enumerating each element within the range.
For most purposes, you won't actually need the Array - Range will work fine. That includes iteration (which is what I assume you want, given the problem you're working on).
That said, knowing how to create such an Array "by hand" is valuable learning experience, so you might want to keep working on it a bit. Hint: you want to start with an empty array ([]) instead with Array.new num, then iterate something num.times, and add numbers into the Array. If you already start with an Array of size num, and then push num elements into it, you'll end up with twice num elements. If, as is your case, you're adding elements while you're iterating the array, the loop never exits, because for each element you process, you add another one. It's like chasing a metal ball with the repulsing side of a magnet.
To answer the Euler Question:
(1 ... 1000).to_a.select{|x| x%3==0 || x%5==0}.reduce(:+) # => 233168
Sometimes a one-liner is more readable than more detailed code i think.
Assuming you are learning Ruby by examples on ProjectEuler, i'll explain what the line does:
(1 ... 1000).to_a
will create an array with the numbers one to 999. Euler-Question wants numbers below 1000. Using three dots in a Range will create it without the boundary-value itself.
.select{|x| x%3==0 || x%5==0}
chooses only elements which are divideable by 3 or 5, and therefore multiples of 3 or 5. The other values are discarded. The result of this operation is a new Array with only multiples of 3 or 5.
.reduce(:+)
Finally this operation will sum up all the numbers in the array (or reduce it to) a single number: The sum you need for the solution.
What i want to illustrate: many methods you would write by hand everyday are already integrated in ruby, since it is a language from programmers for programmers. be pragmatic ;)

Declaring an integer Range with step != 1 in Ruby

UPDATE 2: For posterity, this is how I've settled on doing it (thanks to Jorg's input):
100.step(2, -2) do |x|
# my code
end
(Obviously there are plenty of ways to do this; but it sounds like this is the most "Ruby" way to do it; and that's exactly what I was after.)
UPDATE: OK, so what I was looking for was step:
(2..100).step(2) do |x|
# my code
end
But it turns out that I wasn't 100% forthcoming in my original question. I actually want to iterate over this range backwards. To my surprise, a negative step isn't legal.
(100..2).step(-2) do |x|
# ArgumentError: step can't be negative
end
So: how do I do this backwards?
I am completely new to Ruby, so be gentle.
Say I want to iterate over the range of even numbers from 2 to 100; how would I do that?
Obviously I could do:
(2..100).each do |x|
if x % 2 == 0
# my code
end
end
But, obviously (again), that would be pretty stupid.
I know I could do something like:
i = 2
while i <= 100
# my code
i += 2
end
I believe I could also write my own custom class that provides its own each method (?). I am almost sure that would be overkill, though.
I'm interested in two things:
Is it possible to do this with some variation of the standard Range syntax (i.e., (x..y).each)?
Either way, what would be the most idiomatic "Ruby way" of accomplishing this (using a Range or otherwise)? Like I said, I'm new to the language; so any guidance you can offer on how to do things in a more typical Ruby style would be much appreciated.
You can't declare a Range with a "step". Ranges don't have steps, they simply have a beginning and an end.
You can certainly iterate over a Range in steps, for example like this:
(2..100).step(2).reverse_each(&method(:p))
But if all you want is to iterate, then what do you need the Range for in the first place? Why not just iterate?
100.step(2, -2, &method(:p))
This has the added benefit that unlike reverse_each it does not need to generate an intermediate array.
This question answers yours: about ruby range?
(2..100).step(2) do |x|
# your code
end
I had similar issue here are the various ways I found to do the same SIMPLE thing I used step in the end because it allowed for NEGATIVE and FRACTIONAL increments and I had no conditions, other than the bounds to look for
case loop_type
when FOR
# doen't appear to have a negative or larger than 1 step size!
for kg in 50..120 do
kg_to_stones_lbs(kg)
end
when STEP
120.step(70,-0.5){ |kg|
kg_to_stones_lbs(kg)
}
when UPTO
50.upto(120) { |kg|
kg_to_stones_lbs(kg)
}
when DOWNTO
120.downto(50){ |kg|
kg_to_stones_lbs(kg)
}
when RANGE
(50..120).reverse_each{ |kg|
kg_to_stones_lbs(kg)
}
when WHILE
kg = 120
while kg >= 50
kg_to_stones_lbs(kg)
kg -= 0.5
end
end
O/P:
92.0kg - 14st 7lbs
91.5kg - 14st 6lbs
91.0kg - 14st 5lbs
90.5kg - 14st 4lbs
90.0kg - 14st 2lbs
89.5kg - 14st 1lbs
89.0kg - 14st 0lbs
88.5kg - 13st 13lbs
88.0kg - 13st 12lbs

Code folding on consecutive collect/select/reject/each

I play around with arrays and hashes quite a lot in ruby and end up with some code that looks like this:
sum = two_dimensional_array.select{|i|
i.collect{|j|
j.to_i
}.sum > 5
}.collect{|i|
i.collect{|j|
j ** 2
}.average
}.sum
(Let's all pretend that the above code sample makes sense now...)
The problem is that even though TextMate (my editor of choice) picks up simple {...} or do...end blocks quite easily, it can't figure out (which is understandable since even I can't find a "correct" way to fold the above) where the above blocks start and end to fold them.
How would you fold the above code sample?
PS: considering that it could have 2 levels of folding, I only care about the outer consecutive ones (the blocks with the i)
To be honest, something that convoluted is probably confusing TextMate as much as anyone else who has to maintain it, and that includes you in the future.
Whenever you see something that rolls up into a single value, it's a good case for using Enumerable#inject.
sum = two_dimensional_array.inject(0) do |sum, row|
# Convert row to Fixnum equivalent
row_i = row.collect { |i| i.to_i }
if (row_i.sum > 5)
sum += row_i.collect { |i| i ** 2 }.average
end
sum # Carry through to next inject call
end
What's odd in your example is you're using select to return the full array, allegedly converted using to_i, but in fact Enumerable#select does no such thing, and instead rejects any for which the function returns nil. I'm presuming that's none of your values.
Also depending on how your .average method is implemented, you may want to seed the inject call with 0.0 instead of 0 to use a floating-point value.

Resources