Sorting in Lua, counting number of items - sorting

Two quick questions (I hope...) with the following code. The script below checks if a number is prime, and if not, returns all the factors for that number, otherwise it just returns that the number prime. Pay no attention to the zs. stuff in the script, for that is client specific and has no bearing on script functionality.
The script itself works almost wonderfully, except for two minor details - the first being the factor list doesn't return itself sorted... that is, for 24, it'd return 1, 2, 12, 3, 8, 4, 6, and 24 instead of 1, 2, 3, 4, 6, 8, 12, and 24. I can't print it as a table, so it does need to be returned as a list. If it has to be sorted as a table first THEN turned into a list, I can deal with that. All that matters is the end result being the list.
The other detail is that I need to check if there are only two numbers in the list or more. If there are only two numbers, it's a prime (1 and the number). The current way I have it does not work. Is there a way to accomplish this? I appreciate all the help!
function get_all_factors(number)
local factors = 1
for possible_factor=2, math.sqrt(number), 1 do
local remainder = number%possible_factor
if remainder == 0 then
local factor, factor_pair = possible_factor, number/possible_factor
factors = factors .. ", " .. factor
if factor ~= factor_pair then
factors = factors .. ", " .. factor_pair
end
end
end
factors = factors .. ", and " .. number
return factors
end
local allfactors = get_all_factors(zs.param(1))
if zs.func.numitems(allfactors)==2 then
return zs.param(1) .. " is prime."
else
return zs.param(1) .. " is not prime, and its factors are: " .. allfactors
end

If I understood your problem correctly I recommend splitting up your logic a bit. The idea would be first to create a table containing the fractions and then doing the sort and after that creating the string representation.
-- Creates a table containing all the factors for a number.
function createFactors(n)
local factors = {}
-- The for loop etc. would be here. If you find a factor then add
-- it in the table.
-- ...
table.insert(factors, n)
-- ...
--# Once you've found all the factors just return the table.
return factors
end
-- Lua offers a method for sorting tables called table.sort.
local factors = createFactors(139)
table.sort(factors)
-- There is a method for creating a string representation of a table
-- called table.concat, the first parameter is the table and the second
-- is the character that is used to delimit the values.
table.concat(factors, ", ")

Nice ansewr from ponzao. To put the finishing touches on your result, here's a general-purpose routine for turning a list of strings in Lua into an English string, with "and", that represents the list:
function string.commafy(t, andword)
andword = andword or 'and'
local n = #t
if n == 1 then
return t[1]
elseif n == 2 then
return table.concat { t[1], ' ', andword, ' ', t[2] }
else
local last = t[n]
t[n] = andword .. ' ' .. t[n]
local answer = table.concat(t, ', ')
t[n] = last
return answer
end
end
Instead of table.concat(factors, ', ') use string.commafy(factors).

Related

How can I go on about getting the right output to the user in this recursive function in ruby?

def fibs_rec (n,barray = [])
return 1 if n == 1 || n == 0
a = fibs_rec(n-1,barray) + fibs_rec(n-2,barray)
barray << a
return a
end
for description, This function takes an argument n and prints the first n numbers in the fibonacci sequence but, it isnt quite working as it is supposed to be.
I want it to print the first n fibonacci numbers without any repetitions.
for example if n is 4, output should be 0,1,1,2 instead of 0,1,0,1,1,0,1,1,2. That basically happens when i print barray inside the recursion because i dont have any other option and for that sake i have removed that line.
The thing is I cant remove the return a and replace it with return barray. Not only will that mess up the functionality, fibs_rec is expecting to get a number back to perform the calculations and that wont work when I will return barray just to display the output to the user and neither can I print array because that will keep outputting the new data alongside with the old data and I just want it to be a one single clean output of the whole fibonacci numbers.
For the first question, you cannot remove return a and replace with return barray because
fibs_rec(n-1, barray) + fibs_rec(n-2, barray) will return an array instead of integer.
def fibs_rec(n, barray = [])
return 1 if n == 1 || n == 0
a = fibs_rec(n-1, barray) + fibs_rec(n-2, barray) # a = [2] + [2] wrong!
barray << a
return barray # return an array[]
end
Moreover, according to your problem description, it would be better not to write in a recursive program but if you are required to do a recursive program, I would suggest you that the fibs_rec function you wrote isn't trying to print the pattern but trying to find the fibo number at position n. For example:
# According to your program, you will miss the first 0 of fibonacci sequence
# (0,) 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ……..
fibs_rec(0) # return: 1
fibs_rec(1) # return: 1
fibs_rec(2) # return: 2
fibs_rec(3) # return: 3
fibs_rec(4) # return: 5
. . .
If you want to print out the sequence using recursive function fibs_rec, you will need to create another function to call it from 0 to n.
There are a lot of good resources explaining about Fibonacci and recursive out there. You do not quite understand how recursive works. Try to understand it first. Good luck!

How do I properly use a for loop in Ruby?

I'm trying to improve my Ruby skills using the Project Euler series of questions and I'm wondering why this code does not work for this question: "Even Fibonacci numbers, Problem 2"
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
My code:
def fibo(n)
first, second, sequence = 0,1,[]
for e in n
first, second = second, first + second
sequence << e if e%2 == 0
end
sequence.inject(:+)
end
puts fibo(4000000)
Any help would be appreciated!
In the line:
for e in n
4,000,000 is being substituted for n, so you are saying:
for e in 4000000
which is not a valid statement - you cannot iterate on an integer.
If you would like to iterate through all the values from 0 to n, try:
for e in (0..n)
This iterates through the values in the range 0 to n.
However, there is a deeper problem here. It looks as though you want to iterate up to the value 4000000, but instead your code would iterate through the first 4000000 Fibonacci numbers, which is much more than you want. You may want to consider saying:
while second <= 4000000
I suggest you check out Ruby Koans if you're starting out with Ruby. It's a fun way of getting used to the ways of the language.
That said your code is not calculating Fibonacci correctly, it's not summing the Fibonacci numbers and also has some other errors (for e in n is not valid because n is not an Enumerator type). Fix it like this:
def fibo(n)
first, second, sum = 0, 1, 0
loop do
first, second = second, first + second
sum += second if second%2 == 0
break if second >= n
end
sum
end

Combining two lists with minimum distance between elements

I have to lists like these:
a = ["1a","2a","3a","4a","5a","6a","7a","8a","9a","10a","11a","12a","13a","14a"]
b = ["1b","2b","3b","4b","5b","6b","7b","8b","9b","10b","11b","12b","13b","14b"]
And what I want is to combine them, so that there is at least a difference of n elements between an element from a and it's corresponding element in b.
As an example, if my n is 10, and "3a" is in position 3 and "3b" is in position 5, that isn't a solution since there's only a distance of 2 between these corresponding elements.
I have already solved this for the purpose I want through a brute force method: shuffle the union of the two arrays and see if the constraint is met; if not, shuffle again and so on... Needless to say, that for 14 elements array, sometimes there is 5 to 10 second computation to yield a solution with a minimum distance of 10. Even though that's kind of ok for what I am looking for, I am curious about how I could solve this in a more optimized way.
I am currently using Python, but code in any language (or pseudo-code) is more than welcomed.
EDIT: The context of this problem is something like a questionnarie, in which around 100 participants are expected to join in. Therefore, I am not necessarily interested in all the solutions, but rather something like the first 100.
Thanks.
For your specific scenario, you could use a randomized approach -- though not as random as what you've already tried. Something like this:
start with a random permutation of the items in both lists
create a new permutation by creating a copy of the other and randomly swapping two items
measure the quality of the permutations, e.g., the sum of the distances of each pair of related items, or the minimum of such distances
if the quality of the new permutation is better than that of the original permutation, keep the new one, otherwise discard the new one and continue with the original permutation
repeat from 2. until each distance is at least 10 or until quality does not improve over a number of iterations
The difference to shuffling the whole list in each iteration (as in your approach) is that in each iteration the permutation can only get better, until a satisfying solution is found.
Each time you run this algorithm, the result will be slightly different, so you can run it 100 times for 100 different solutions. Of course, this algorithm does not guarantee to find a solution (much less all such solutions), but it should be fast enough so that you could just restart it in case it fails.
In Python, this could look somewhat like this (slightly simplified, but still working):
def shuffle(A, B):
# original positions, i.e. types of questions
kind = dict([(item, i) for i, item in list(enumerate(A)) + list(enumerate(B))])
# get positions of elements of kinds, and return sum of their distances
def quality(perm):
pos = dict([(kind[item], i) for i, item in enumerate(perm)])
return sum(abs(pos[kind[item]] - i) for i, item in enumerate(perm))
# initial permutation and quality
current = A + B
random.shuffle(current)
best = quality(current)
# improve upon initial permutation by randomly swapping items
for g in range(1000):
i = random.randint(0, len(current)-1)
j = random.randint(0, len(current)-1)
copy = current[:]
copy[i], copy[j] = copy[j], copy[i]
q = quality(copy)
if q > best:
current, best = copy, q
return current
Example output for print shuffle(a, b):
['14b', '2a', '13b', '3a', '9b', '4a', '6a', '1a', '8a', '5b', '12b', '11a', '10b', '7b', '4b', '11b', '5a', '7a', '8b', '12a', '13a', '14a', '1b', '2b', '3b', '6b', '10a', '9a']
As I understand from your question, it is possible to perform all the ordering by relying exclusively on the indices of the arrays (i.e., on pure integers) and thus the problem can be reduced to create (valid) ranges instead of analysing each element.
for each a <= total_items-n , valid b = if(a + n == total_items){total_items} else{[a + n, total_items]}
For example:
n = 10;
total_items = 15;
for a = 1 -> valid b = [11, 15]
for a = 2 -> valid b = [12, 15]
, etc.
This would be perfomed 4 times: forwards and backwards for a respect to b and the same for b respect to a.
In this way you would reduce the number of iterations to its minimum expression and would get, as an output, a set of "solutions" for each position, rather than a one-to-one binding (that is what you have right now, isn't it?).
If there are equivalents in Python to .NET's Lists and LINQ, then you may be able to directly convert the following code. It generates up to 100 lists really quickly: I press "debug" to run it and up pops a windows with the results in much less than a second.
' VS2012
Option Infer On
Module Module1
Dim minDistance As Integer = 10
Dim rand As New Random ' a random number generator
Function OkToAppend(current As List(Of Integer), x As Integer) As Boolean
' see if the previous minDistance values contain the number x
Return Not (current.Skip(current.Count - minDistance).Take(minDistance).Contains(x))
End Function
Function GenerateList() As List(Of String)
' We don't need to start with strings: integers will make it faster.
' The "a" and "b" suffixes can be sprinkled on at random once the
' list is created.
Dim numbersToUse() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
Dim pool As New List(Of Integer)
' we need all the numbers twice
pool.AddRange(numbersToUse)
pool.AddRange(numbersToUse)
Dim newList As New List(Of Integer)
Dim pos As Integer
For i = 0 To pool.Count - 1
' limit the effort it puts in
Dim sanity As Integer = pool.Count * 10
Do
pos = rand.Next(0, pool.Count)
sanity -= 1
Loop Until OkToAppend(newList, pool(pos)) OrElse sanity = 0
If sanity > 0 Then ' it worked
' append the value to the list
newList.Add(pool(pos))
' remove the value which has been used
pool.RemoveAt(pos)
Else ' give up on this arrangement
Return Nothing
End If
Next
' Create the final list with "a" and "b" stuck on each value.
Dim stringList As New List(Of String)
Dim usedA(numbersToUse.Length) As Boolean
Dim usedB(numbersToUse.Length) As Boolean
For i = 0 To newList.Count - 1
Dim z = newList(i)
Dim suffix As String = ""
If usedA(z) Then
suffix = "b"
ElseIf usedB(z) Then
suffix = "a"
End If
' rand.Next(2) generates an integer in the range [0,2)
If suffix.Length = 0 Then suffix = If(rand.Next(2) = 1, "a", "b")
If suffix = "a" Then
usedA(z) = True
Else
usedB(z) = True
End If
stringList.Add(z.ToString & suffix)
Next
Return stringList
End Function
Sub Main()
Dim arrangements As New List(Of List(Of String))
For i = 1 To 100
Dim thisArrangement = GenerateList()
If thisArrangement IsNot Nothing Then
arrangements.Add(thisArrangement)
End If
Next
'TODO: remove duplicate entries and generate more to make it up to
' the required quantity.
For Each a In arrangements
' outputs the elements of a with ", " as a separator
Console.WriteLine(String.Join(", ", a))
Next
' wait for user to press enter
Console.ReadLine()
End Sub
End Module

Randomize numbers in Lua with no repeats

I am doing a project in Lua which involves randomizing numbers without repeats. Here's my code
for i = 1, 86000 do
while rndom[num] ~= nil do
num = math.random(1,95000)
end
rndom[num] = num
for k=1, 11 do
file2:write(input[num][k], " ")
end
file2:write("\n")
end
Basically it puts a value to the rndom[num] so that when randomized number repeats and rndom[num] ~= nil, it will randomize number again. My problem is, it's taking too long to load as my 'i' gets higher and there will come a time that it will stop. I'm guessing it's because randomizer can't get a rndom[num] that's 'nil'. I mean, what are the odds right? I'd like to improve the running time of it. Anyone who can suggest a better solution to my problem?
Thanks!
It is better to generate a permutation with O(N) time complexity.
local n = 95000
local t = {}
for i = 1, n do
t[i] = i
end
for i = 1, 86000 do
local j = math.random(i, n)
t[i], t[j] = t[j], t[i]
for k = 1, 11 do
file2:write(input[t[i]][k], " ")
end
file2:write"\n"
end
One simple solution is instead of using random again when you get a variable you already have, trying to return the next one available. That way you are guaranteed to have O(N^2) running time (maximum).

Working with arbitrary inequalities and checking which, if any, are satisfied

Given a non-negative integer n and an arbitrary set of inequalities that are user-defined (in say an external text file), I want to determine whether n satisfies any inequality, and if so, which one(s).
Here is a points list.
n = 0: 1
n < 5: 5
n = 5: 10
If you draw a number n that's equal to 5, you get 10 points.
If n less than 5, you get 5 points.
If n is 0, you get 1 point.
The stuff left of the colon is the "condition", while the stuff on the right is the "value".
All entries will be of the form:
n1 op n2: val
In this system, equality takes precedence over inequality, so the order that they appear in will not matter in the end. The inputs are non-negative integers, though intermediary and results may not be non-negative. The results may not even be numbers (eg: could be strings). I have designed it so that will only accept the most basic inequalities, to make it easier for writing a parser (and to see whether this idea is feasible)
My program has two components:
a parser that will read structured input and build a data structure to store the conditions and their associated results.
a function that will take an argument (a non-negative integer) and return the result (or, as in the example, the number of points I receive)
If the list was hardcoded, that is an easy task: just use a case-when or if-else block and I'm done. But the problem isn't as easy as that.
Recall the list at the top. It can contain an arbitrary number of (in)equalities. Perhaps there's only 3 like above. Maybe there are none, or maybe there are 10, 20, 50, or even 1000000. Essentially, you can have m inequalities, for m >= 0
Given a number n and a data structure containing an arbitrary number of conditions and results, I want to be able to determine whether it satisfies any of the conditions and return the associated value. So as with the example above, if I pass in 5, the function will return 10.
They condition/value pairs are not unique in their raw form. You may have multiple instances of the same (in)equality but with different values. eg:
n = 0: 10
n = 0: 1000
n > 0: n
Notice the last entry: if n is greater than 0, then it is just whatever you got.
If multiple inequalities are satisfied (eg: n > 5, n > 6, n > 7), all of them should be returned. If that is not possible to do efficiently, I can return just the first one that satisfied it and ignore the rest. But I would like to be able to retrieve the entire list.
I've been thinking about this for a while and I'm thinking I should use two hash tables: the first one will store the equalities, while the second will store the inequalities.
Equality is easy enough to handle: Just grab the condition as a key and have a list of values. Then I can quickly check whether n is in the hash and grab the appropriate value.
However, for inequality, I am not sure how it will work. Does anyone have any ideas how I can solve this problem in as little computational steps as possible? It's clear that I can easily accomplish this in O(n) time: just run it through each (in)equality one by one. But what happens if this checking is done in real-time? (eg: updated constantly)
For example, it is pretty clear that if I have 100 inequalities and 99 of them check for values > 100 while the other one checks for value <= 100, I shouldn't have to bother checking those 99 inequalities when I pass in 47.
You may use any data structure to store the data. The parser itself is not included in the calculation because that will be pre-processed and only needs to be done once, but if it may be problematic if it takes too long to parse the data.
Since I am using Ruby, I likely have more flexible options when it comes to "messing around" with the data and how it will be interpreted.
class RuleSet
Rule = Struct.new(:op1,:op,:op2,:result) do
def <=>(r2)
# Op of "=" sorts before others
[op=="=" ? 0 : 1, op2.to_i] <=> [r2.op=="=" ? 0 : 1, r2.op2.to_i]
end
def matches(n)
#op2i ||= op2.to_i
case op
when "=" then n == #op2i
when "<" then n < #op2i
when ">" then n > #op2i
end
end
end
def initialize(text)
#rules = text.each_line.map do |line|
Rule.new *line.split(/[\s:]+/)
end.sort
end
def value_for( n )
if rule = #rules.find{ |r| r.matches(n) }
rule.result=="n" ? n : rule.result.to_i
end
end
end
set = RuleSet.new( DATA.read )
-1.upto(8) do |n|
puts "%2i => %s" % [ n, set.value_for(n).inspect ]
end
#=> -1 => 5
#=> 0 => 1
#=> 1 => 5
#=> 2 => 5
#=> 3 => 5
#=> 4 => 5
#=> 5 => 10
#=> 6 => nil
#=> 7 => 7
#=> 8 => nil
__END__
n = 0: 1
n < 5: 5
n = 5: 10
n = 7: n
I would parse the input lines and separate them into predicate/result pairs and build a hash of callable procedures (using eval - oh noes!). The "check" function can iterate through each predicate and return the associated result when one is true:
class PointChecker
def initialize(input)
#predicates = Hash[input.split(/\r?\n/).map do |line|
parts = line.split(/\s*:\s*/)
[Proc.new {|n| eval(parts[0].sub(/=/,'=='))}, parts[1].to_i]
end]
end
def check(n)
#predicates.map { |p,r| [p.call(n) ? r : nil] }.compact
end
end
Here is sample usage:
p = PointChecker.new <<__HERE__
n = 0: 1
n = 1: 2
n < 5: 5
n = 5: 10
__HERE__
p.check(0) # => [1, 5]
p.check(1) # => [2, 5]
p.check(2) # => [5]
p.check(5) # => [10]
p.check(6) # => []
Of course, there are many issues with this implementation. I'm just offering a proof-of-concept. Depending on the scope of your application you might want to build a proper parser and runtime (instead of using eval), handle input more generally/gracefully, etc.
I'm not spending a lot of time on your problem, but here's my quick thought:
Since the points list is always in the format n1 op n2: val, I'd just model the points as an array of hashes.
So first step is to parse the input point list into the data structure, an array of hashes.
Each hash would have values n1, op, n2, value
Then, for each data input you run through all of the hashes (all of the points) and handle each (determining if it matches to the input data or not).
Some tricks of the trade
Spend time in your parser handling bad input. Eg
n < = 1000 # no colon
n < : 1000 # missing n2
x < 2 : 10 # n1, n2 and val are either number or "n"
n # too short, missing :, n2, val
n < 1 : 10x # val is not a number and is not "n"
etc
Also politely handle non-numeric input data
Added
Re: n1 doesn't matter. Be careful, this could be a trick. Why wouldn't
5 < n : 30
be a valid points list item?
Re: multiple arrays of hashes, one array per operator, one hash per point list item -- sure that's fine. Since each op is handled in a specific way, handling the operators one by one is fine. But....ordering then becomes an issue:
Since you want multiple results returned from multiple matching point list items, you need to maintain the overall order of them. Thus I think one array of all the point lists would be the easiest way to do this.

Resources