For some reason, string is getting rewritten as mirror by the operation mirror[j] = string[i]
I have no idea why this would be, I'm not commanding it to. The outputs of my reverse(string) function will stop at the middle, like:
ABCDEF -> FEDDEF
but I'm trying to do:
ABCDEF -> FEDCBA
def reverse(string)
mirror = string
i = string.length - 1
j = 0
while j < string.length
mirror[j] = string[i]
puts(mirror)
j = j + 1
i = i - 1
end
return mirror
end
You need to use #dup. In your case, mirror = string means both the variables are holding the reference of the same object. So, when you change the object, that can be reflected through both string and mirror.
def reverse(string)
mirror = string.dup
i = string.length - 1
j = 0
while j < string.length
mirror[j] = string[i]
j += 1 # same as j = j + 1
i -= 1 # same as i = i - 1
end
mirror
# last expression is returned by default, so you can write only `mirror` instead of `return mirror`
end
p reverse 'ABCDEF' # "FEDCBA"
Related
I'm currently trying to run a lua script to find the future values of a static rng seed from "Fire Emblem - Seisen no Keifu" in the snes9x-1.52-rr-r185 emulator by reading the memory values.
Unfortunately I get the following message when i run the code: "rng.lua:26: attempt to call field 'text' (a nil value)"
The code is below:
emu = snes9x
function get_rng()
return {
step = memory.readbyte(0x7e04a2),
table = memory.readbyterange(0x7e046b,0x37)
}
end
function rand(rng)
rng.step = rng.step + 1
if rng.step >= 0x37 then
for i = 0, 0x36 do
local j if i < 0x18 then j = i+0x1f else j = i-0x18 end
rng.table[i+1] = rng.table[i+1] - rng.table[j+1]
if rng.table[i+1] < 0 then rng.table[i+1] = rng.table[i+1] + 100 end
end
rng.step = 0
end
local res = rng.table[rng.step+1]-1
if res < 0 then res = 99 end
return res
end
while true do
local rng = get_rng()
for i = 1, 0x10 do
gui.text(i*12, 0,string.format("%02x",rng.step))
gui.text(i*12,10,string.format("%2u",rand(rng)))
end
emu.frameadvance()
end
I expected the rng values to be shown on screen but got the aforementioned message.
Is there a way if a string is close to a string in a table it will replace it with the one in the table?
Like a spellcheck function, that searches through a table and if the input is close to one in the table it will fix it , so the one in the table and the string is the same?
You can use this code :) Reference code is from here : https://github.com/badarsh2/Algorithm-Implementations/blob/master/Levenshtein_distance/Lua/Yonaba/levenshtein.lua
local function min(a, b, c)
return math.min(math.min(a, b), c)
end
local function matrix(row,col)
local m = {}
for i = 1,row do m[i] = {}
for j = 1,col do m[i][j] = 0 end
end
return m
end
local function lev(strA,strB)
local M = matrix(#strA+1,#strB+1)
local i, j, cost
local row, col = #M, #M[1]
for i = 1, row do M[i][1] = i - 1 end
for j = 1, col do M[1][j] = j - 1 end
for i = 2, row do
for j = 2, col do
if (strA:sub(i - 1, i - 1) == strB:sub(j - 1, j - 1)) then cost = 0
else cost = 1
end
M[i][j] = min(M[i-1][j] + 1,M[i][j - 1] + 1,M[i - 1][j - 1] + cost)
end
end
return M[row][col]
end
local refTable = {"hell", "screen"}
local function getClosestWord(pInput, pTable, threesold)
cDist = -1
cWord = ""
for key, val in pairs(pTable) do
local levRes = lev(pInput, val)
if levRes < cDist or cDist == -1 then
cDist = levRes
cWord = val
end
end
print(cDist)
if cDist <= threesold then
return cWord
else
return pInput
end
end
a = getClosestWord("hello", refTable, 3)
b = getClosestWord("screw", refTable, 3)
print(a, b)
Third parameter is threesold, if min distance is higher than threesold, word is not replaced.
def most_common_letter(string)
letter = nil
final_letter = nil
letter_count = nil
idx1 = 0
idx2 = 0
count = 0
while idx1 < string.length
letter = string[idx1]
while idx2 < string.length
if letter == string[idx2]
count += 1
end
idx2 += 1
end
if (letter_count == nil) || (count > letter_count)
letter_count = count
final_letter = letter
end
idx1 += 1
end
arr = []
arr.push(final_letter)
arr.push(letter_count)
return arr
end
puts(most_common_letter("abbab") == ["b", 3])
#should be true
Keep getting [a,2] which leads me to believe it is only executing parts of the code when in my mind the code should be resetting the value of final letter and letter count every time there is a more frequent letter. Where have I gone wrong?
Often a counting hash is used for this type of problem:
def most_frequent_letter(str)
str.each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }.max_by(&:last)
end
most_frequent_letter("bananas are so-so")
#=> ["a",4]
The steps:
h = "bananas are so-so".each_char.with_object(Hash.new(0)) { |c,h| h[c] += 1 }
#=> {"b"=>1, "a"=>4, "n"=>2, "s"=>3, " "=>2, "r"=>1, "e"=>1, "o"=>2, "-"=>1}
h.max_by(&:last)
#=> ["a",4]
Here is an easier way to solve this:
def most_common_letter(string)
letters = string.split('').sort!
frequency = letters.inject(Hash.new(0)) { |h,v| h[v] += 1; h }
frequency.max_by{|k,v| v}
end
most_common_letter("abbab")
=> ["b", 3]
Let me go through this code line-by-line to explain.
1) Get the letters of the string and sort them alphabetically:
string = "abbab"
letters = string.split('').sort!
=> ["a", "a", "b", "b", "b"]
2) Create a hash with keys (letters) and values (occurrence)
frequency = letters.inject(Hash.new(0)) { |h,v| h[v] += 1; h }
=> {"a"=>2, "b"=>3}
3) Find the highest value, and return the key value pair as an array.
frequency.max_by{|k,v| v}
=> ["b", 3]
The problem you are running into is that you are not resetting your idx2 after the loop.
You can debug this if you puts the idx two as follows:
def most_common_letter(string)
letter = nil
final_letter = nil
letter_count = nil
idx1 = 0
idx2 = 0
count = 0
while idx1 < string.length
letter = string[idx1]
while idx2 < string.length
if letter == string[idx2]
count += 1
end
idx2 += 1
end
puts "#{idx2}" #=> This is always 5
if (letter_count == nil) || (count > letter_count)
letter_count = count
final_letter = letter
end
idx1 += 1
end
arr = []
arr.push(final_letter)
arr.push(letter_count)
return arr
end
puts(most_common_letter("abbab"))
Your algorithm is simply doing the following:
comparing idx1 with idx2:
str[0] with str[0]
str[0] with str[1]
str[0] with str[2]
str[0] with str[3]
str[0] with str[4]
then idx2 is out of range and will never satisfy idx2 < string.length again, because the value is not reset.
This is where the logical error is. I won't give you another solution because it seems like you are trying to figure this out on your own. Hope this helps.
Try this
def most_common_letter(str)
str.chars.
group_by{|v| v}.
map{|k, l| [k, l.size]}.
sort_by{|k, size| size}.
last
end
Now:
puts(most_common_letter("abbab") == ["b", 3])
# true
Write a method that takes in a string of lowercase letters (no uppercase letters, no repeats). Consider the substrings of the string: consecutive sequences of letters contained inside the string.
Find the longest such string of letters that is a palindrome.
Based on local method Palindrome?(string), I implemented longest-palindrome(string) as below with test cases:
def palindrome?(string)
i = 0
while i < string.length
if string[i] != string[(string.length - 1) - i]
return false
end
i += 1
end
return true
end
def longest_palindrome(string)
dix = 0
lstr = ""
lstrc = nil
while dix < string.length
dix2 = 1
while dix2 < string.length
str = string.slice(dix,dix2)
count = str.length
if palindrome?(str)
if lstrc == nil || lstrc < count
lstr = str
lstrc = count
end
end
dix2 += 1
end
dix += 1
end
puts(lstr)
return lstr
end
# These are tests to check that your code is working. After writing
# your solution, they should all print true.
puts(
'longest_palindrome("abcbd") == "bcb": ' +
(longest_palindrome('abcbd') == 'bcb').to_s
)
puts(
'longest_palindrome("abba") == "abba": ' +
(longest_palindrome('abba') == 'abba').to_s
)
puts(
'longest_palindrome("abcbdeffe") == "effe": ' +
(longest_palindrome('abcbdeffe') == 'effe').to_s
)
Test results as below:
bcb
longest_palindrome("abcbd") == "bcb": true
bb
longest_palindrome("abba") == "abba": false
effe
longest_palindrome("abcbdeffe") == "effe": true
Why did the second test failed?
... this line is preventing you from considering the entire string
while dix2 < string.length
So when dix is the whole string, you're not doing any testing for palindromes
Change the line to...
while dix2 <= string.length
It would actually be slightly more efficient if you did...
while dix2 <= string.length - dix
Which would prevent you from testing (for, say, a string of length 10), string(7,3) and string(7,4) and string(7,5) etc. etc., which are all basically the same string.
I can't seem to get my head around the rules that govern these two cases:
1. The end index may be one less than the start index, producing an empty array/string.
2. It's apparently legal to position the start index just behind the last element, if the end index is one less, as before.
[|0..2|].[3..2];; // [||]
"bar".[3..2];; // ""
A naive implementation of bound checks with consideration of case 1 wouldn't allow case 2:
let trySlice i j (a : string) =
let lastIdx = a.Length - 1
if i < 0 || i > lastIdx || j < i - 1 || j > lastIdx then None
else Some a.[i..j]
trySlice 3 2 "bar" // None
What's the rationale behind this behavior? How to proceed?
Edit
This is what I have now thanks to Tarmil's input
let trySlice i j (a : string) =
if i >= 0 && j >= i - 1 && j < a.Length then Some a.[i..j]
else None
which should be equivalent to
let trySlice' i j (s : string) =
try s.Substring(i, j - i + 1) |> Some
with _ -> None
I suppose the rationale is that a.[i..j] is a sequence of length (j - i + 1), so in a way it makes sense to allow i = j + 1 as a way to extract an empty sequence.
As for "how to proceed", if you want your trySlice to accept all cases that the built-in slicing accepts, then just remove the i > lastIdx clause. When i = lastIdx + 1, the only way for the other conditions to pass is if j = lastIdx, and when i > lastIdx + 1, there is no way for j to pass both its constraints.
As a side-note, the way you write:
if (failCondition || failCondition || ...) then None else Some x
feels counter-intuitive to me for some reason, I would have written it as:
if (successCondition && successCondition && ...) then Some x else None