No Output for the Elixir Program - erlang

I am trying to solve a dynamic problem finding the subsets i have written the code but i didn't know why i am not getting anything it just blinks after running Todos.sum_of_one(arr_of_digits, sum_val), I think the problem is in the terminating case when n==0, can anyone please tell me where is the mistake
def Todos do
#find all the subsets whose sum is equal to sum_val
def sumofone(arr_of_digits,n,v,sum)do
if(sum==0) do
for i <- v do
i
end
end
#return if n becomes 0
if(n==0) do
v
end
sumofone(arr_of_digits,n-1,v,sum)
k = Enum.at(arr_of_digits,n-1)
#inserting the element in the list
[k | v]
sumofone(arr_of_digits,n-1,v,sum - arr_of_digits[n-1]);
end
def sum_of_one(arr_of_digits, sum_val) do
v = []
sumofone(arr_of_digits,l,v,sum_val)
end
end

It looks like you're trying to return from the function in the two if expressions. Elixir doesn't work that way - it always* runs through the entire function and returns the value of the last expression in the function.
One way to get around this is to break up the code into different function clauses, where each clause matches one of the conditions you're testing for:
# This clause executes when the fourth argument is 0
def sumofone(_arr_of_digits,_n,v,0) do
for i <- v do
i
end
end
# This clause executes when the second argument is 0
def sumofone(_arr_of_digits,0,v,_sum) do
v
end
# This clause executes in all other cases, as long as n is greater than 0
def sumofone(arr_of_digits,n,v,sum) when n > 0 do
sumofone(arr_of_digits,n-1,v,sum)
k = Enum.at(arr_of_digits,n-1)
#inserting the element in the list
[k | v]
sumofone(arr_of_digits,n-1,v,sum - arr_of_digits[n-1]);
end
With this change, it's guaranteed that the function will actually terminate. It still won't do what you expect it to do, since there are two lines that calculate a value but throw it away. In Elixir, if you want to update the value of a variable, you need to do so explicitly. Did you mean something like this?
sum = sumofone(arr_of_digits,n-1,v,sum)
and
#inserting the element in the list
v = [k | v]
But I'll leave that for you to debug.
Note that I prefixed some of the argument names with an underscore. Without that, the compiler would give a warning about the variable being unused. With the underscore, it's clear that this is in fact intended.
* Except if you're using errors, throws and exits. But try not to use them - it's often clearer not to.

Related

Why is this function to add the contents of a table together in Lua returning nothing

I am stuck trying to make the contese of a table (all integers) add together to form one sum. I am working on a project where the end goal is a percentage. I am putting the various quantities and storing them in one table. I want to then add all of those integers in the table together to get a sum. I haven't been able to find anything in the standard Library, so I have been tyring to use this:
function sum(t)
local sum = 0
for k,v in pairs(t) do
sum = sum + v
end
return sum
However, its not giving me anything after return sum.... Any and all help would be greatly appreciated.
A more generic solution to this problem of reducing the contents of a table (in this case by summing the elements) is outlined in this answer (warning: no type checking in code sketch).
If your function is not returning at all, it is probably because you are missing an end statement in the function definition.
If your function is returning zero, it is possible that there is a problem with the table you are passing as an argument. In other words, the parameter t may be nil or an empty table. In that case, the function would return zero, the value to which your local sum is initialized.
If you add print (k,v) in the loop for debugging, you can determine whether the function has anything to add. So I would try:
local function sum ( t ) do
print( "t", t ) -- for debugging: should not be nil
local s = 0
for k,v in pairs( t ) do
print(k,v) --for debugging
s = s + v
end
return s
end
local myTestData = { 1, 2, 4, 9 }
print( sum( myTestData) )
The expected output when running this code is
t table: [some index]
1 1
2 2
3 4
4 9
16
Notice that I've changed the variable name inside the function from sum to s. It's preferable not to use the function name sum as the variable holding the sum in the function definition. The local sum in the function overrides the global one, so for example, you couldn't call sum() recursively (i.e. call sum() in the definition of sum()).

Ruby inject to create array

I have this code
notebooks.inject([]) do |res, nb|
res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)
end
The first nb has matches the condition and res looks like this
["xxx1234"]
The second nb does not match the condition which then delete/clears res
nil
From my understanding, the first value should remain in the array.
I'm also assigning this to a variable and want it to be a one liner.
inject works a little differently from how you're imagining. It simply returns the last return value of the loop as it loops through each item. An easy way to fix this is:
notebooks.inject([]) do |res, nb|
res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)
res # Returns the res array
end
That said, you should probably use select for your use case as you seem to be just filtering down which set of notebooks you want.. That is:
notebooks.select{|nb| Recipe::NOTEBOOKS.include?(nb.name)}.map(&:guid)
Generally, I've used inject when I need to run math on a group of items. e.g.
[1,2,3,4].inject(0) {|res, x| x * 2 + res}
If you're open to two loops, but cleaner and still one-liner:
notebooks.select { |nb| Recipe::NOTEBOOKS.include?(nb.name) }.map(&:guid)
The accumulator must be returned on each loop iteration:
notebooks.inject([]) do |res, nb|
Recipe::NOTEBOOKS.include?(nb.name) ? res << nb.guid : res
end
Actually, on each subsequent loop iteration, the accumulator passed to res block parameter is exactly what was returned from the previous iteration.
In your example, on the second iteration if returns false and
res << nb.guid if Recipe::NOTEBOOKS.include?(nb.name)
line is not executed at all. That said, after the second iteration, the accumulator takes a brand new value, that is apparently nil.

Ruby method returns hash values in binary

I wrote a method that takes six names then generates an array of seven random numbers using four 6-sided dice. The lowest value of the four 6-sided dice is dropped, then the remainder is summed to create the value. The value is then added to an array.
Once seven numbers have been generated, the array is then ordered from highest to lowest and the lowest value is dropped. Then the array of names and the array of values are zipped together to create a hash.
This method ensures that the first name in the array of names receives the highest value, and the last name receives the lowest.
This is the result of calling the method:
{:strength=>1, :dexterity=>1, :constitution=>0, :intelligence=>0, :wisdom=>0, :charisma=>1}
As you can see, all the values I receive are either "1" or "0". I have no idea how this is happening.
Here is the code:
module PriorityStatGenerator
def self.roll_stats(first_stat, second_stat, third_stat, fourth_stat, fifth_stat, sixth_stat)
stats_priority = [first_stat, second_stat, third_stat, fourth_stat, fifth_stat, sixth_stat].map(&:to_sym)
roll_array = self.roll
return Hash[stats_priority.zip(roll_array)]
end
private
def self.roll
roll_array = []
7.times {
roll_array << Array.new(4).map{ 1 + rand(6) }.sort.drop(1).sum
}
roll_array.reverse.delete_at(6)
end
end
This is how I'm calling the method while I'm testing:
render plain: PriorityStatGenerator.roll_stats(params[:prioritize][:first_stat], params[:prioritize][:second_stat], params[:prioritize][:third_stat], params[:prioritize][:fourth_stat], params[:prioritize][:fifth_stat], params[:prioritize][:sixth_stat])
I added require 'priority_stat_generator' where I'm calling the method, so it is properly calling it.
Can someone help me make it return proper values between 1 and 18?
Here's a refactoring to simplify things and use an actually random number generator, as rand is notoriously terrible:
require 'securerandom'
module PriorityStatGenerator
def self.roll_stats(*stats)
Hash[
stats.map(&:to_sym).zip(self.roll(stats.length).reverse)
]
end
private
def self.roll(n = 7)
(n + 1).times.map do
4.times.map { 1 + SecureRandom.random_number(6) }.sort.drop(1).inject(:+)
end.sort.last(n)
end
end
This makes use of inject(:+) so it works in plain Ruby, no ActiveSupport required.
The use of *stats makes the roll_stats function way more flexible. Your version has a very rigid number of parameters, which is confusing and often obnoxious to use. Treating the arguments as an array avoids a lot of the binding on the expectation that there's six of them.
As a note it's not clear why you're making N+1 roles and then discarding the last. That's the same as generating N and discarding none. Maybe you meant to sort them and take the N best?
Update: Added sort and reverse to properly map in terms of priority.
You need to learn to use IRB or PRY to test snippets of your code, or better, learn to use a debugger. They give you insight into what your code is doing.
In IRB:
[7,6,5,4,3,2,1].delete_at(6)
1
In other words, delete_at(6) is doing what it's supposed to, but that's not what you want. Instead, perhaps slicing the array will behave more like you expect:
>> [7,6,5,4,3,2,1][0..-2]
[
[0] 7,
[1] 6,
[2] 5,
[3] 4,
[4] 3,
[5] 2
]
Also, in your code, it's not necessary to return a value when that operation is the last logical step in a method. Ruby will return the last value seen:
Hash[stats_priority.zip(roll_array)]
As amadan said, I can't see how you are getting the results you are, but their is a definite bug in your code.
The last line in self.roll is the return value.
roll_array.reverse.delete_at(6)
Which is going to return the value that was deleted. You need to add a new lines to return the roll_array instead of the delete_at value. You are also not sorting your array prior to removing that last item which will give you the wrong values as well.
def self.roll
roll_array = []
7.times {
roll_array << Array.new(4).map{ 1 + rand(6) }.sort.drop(1).sum
}
roll_array.sort.drop(1)
roll_array
end

How do I retain the value of a for loop variable when the loop is over?

I'm trying to find something in a loop in Lua, and when I'm done I need to use the location I found.
for j = 1,100 do
<do some stuff>
if <some test> then
break
end
end
if j >= 100 then
return
end
Unfortunately, I get an error which suggests that after the for loop exits, the value of j is nil. How do I use the value that j ended at? Obviously I could create an extra variable and assign it right before I break, but that just seems wrong, and I've never seen another language set the loop variable to nil when the loop ends, so I'm wondering if there isn't a better way to accomplish this.
The loop variable is only visible inside the for loop block. You can get around this by creating another variable as suggested in PIL 4.3.4 Numeric For.
local index
for j=1,100 do
if j == 10 then
index = j
end
end
Alternatively, if you are a doing a common operation then using a function with an early return may be best.
function find(tbl, val)
for i, v in ipairs(tbl) do
if v == val then
return i
end
end
end

Generate a powerset without a stack in Erlang

Note: This is a sequel to my previous question about powersets.
I have got a nice Ruby solution to my previous question about generating a powerset of a set without a need to keep a stack:
class Array
def powerset
return to_enum(:powerset) unless block_given?
1.upto(self.size) do |n|
self.combination(n).each{|i| yield i}
end
end
end
# demo
['a', 'b', 'c'].powerset{|item| p item} # items are generated one at a time
ps = [1, 2, 3, 4].powerset # no block, so you'll get an enumerator
10.times.map{ ps.next } # 10.times without a block is also an enumerator
It does the job and works nice.
However, I would like to try to rewrite the same solution in Erlang, because for the {|item| p item} block I have a big portion of working code already written in Erlang (it does some stuff with each generated subset).
Although I have some experience with Erlang (I have read all 2 books :)), I am pretty confused with the example and the comments that sepp2k kindly gave me to my previous question about powersets. I do not understand the last line of the example - the only thing that I know is that is is a list comprehension. I do not understand how I can modify it to be able to do something with each generated subset (then throw it out and continue with the next subset).
How can I rewrite this Ruby iterative powerset generation in Erlang? Or maybe the provided Erlang example already almost suits the need?
All the given examples have O(2^N) memory complexity, because they return whole result (the first example). Two last examples use regular recursion so that stack raises. Below code which is modification and compilation of the examples will do what you want:
subsets(Lst) ->
N = length(Lst),
Max = trunc(math:pow(2, N)),
subsets(Lst, 0, N, Max).
subsets(Lst, I, N, Max) when I < Max ->
_Subset = [lists:nth(Pos+1, Lst) || Pos <- lists:seq(0, N-1), I band (1 bsl Pos) =/= 0],
% perform some actions on particular subset
subsets(Lst, I+1, N, Max);
subsets(_, _, _, _) ->
done.
In the above snippet tail recursion is used which is optimized by Erlang compiler and converted to simple iteration under the covers. Recursion may be optimized this way only if recursive call is the last one within function execution flow. Note also that each generated Subset may be used in place of the comment and it will be forgotten (garbage collected) just after that. Thanks to that neither stack nor heap won't grow, but you also have to perform operation on subsets one after another as there's no final result containing all of them.
My code uses same names for analogous variables like in the examples to make it easier to compare both of them. I'm sure it could be refined for performance, but I only want to show the idea.

Resources