A calculator using Lua string matching - string

I've recently playing around with string manipulation to try to make a calculator that takes only one string and returns an answer. I know I could simply use loadstring to do this, but I am trying to learn more about string manipulation. This is what I have so far: Is there any way I can make it more efficient?
function calculate(exp)
local x, op, y =
string.match(exp, "^%d"),
string.match(exp, " %D"),
string.match(exp, " %d$")
x, y = tonumber(x), tonumber(y)
op = op:sub(string.len(op))
if (op == "+") then
return x + y
elseif (op == "-") then
return x - y
elseif (op == "*") then
return x * y
elseif (op == "/") then
return x / y
else
return 0
end
end
print(calculate("5 + 5"))

You can use captures in the matching pattern to reduce the number of calls to string.match().
local x, op, y = string.match(exp, "^(%d) (%D) (%d)$")
This also eliminates the need to trim the op result.
The conversion tonumber() does not need to be called for x and y. These will automatically be converted when used with the numeric operators.

Related

How convert first char to lowerCase

Try to play with string and I have string like: "Hello.Word" or "stackOver.Flow"
and i what first char convert to lower case: "hello.word" and "stackOver.flow"
For snakeCase it easy we need only change UpperCase to lower and add '_'
but in camelCase (with firs char in lower case) i dont know how to do this
open System
let convertToSnakeCase (value:string) =
String [|
Char.ToLower value.[0]
for ch in value.[1..] do
if Char.IsUpper ch then '_'
Char.ToLower ch |]
Who can help?
module Identifier =
open System
let changeCase (str : string) =
if String.IsNullOrEmpty(str) then str
else
let isUpper = Char.IsUpper
let n = str.Length
let builder = new System.Text.StringBuilder()
let append (s:string) = builder.Append(s) |> ignore
let rec loop i j =
let k =
if i = n (isUpper str.[i] && (not (isUpper str.[i - 1])
((i + 1) <> n && not (isUpper str.[i + 1]))))
then
if j = 0 then
append (str.Substring(j, i - j).ToLower())
elif (i - j) > 2 then
append (str.Substring(j, 1))
append (str.Substring(j + 1, i - j - 1).ToLower())
else
append (str.Substring(j, i - j))
i
else
j
if i = n then builder.ToString()
else loop (i + 1) k
loop 1 0
type System.String with
member x.ToCamelCase() = changeCase x
printfn "%s" ("StackOver.Flow".ToCamelCase()) //stackOver.Flow
//need stackOver.flow
I suspect there are much more elegant and concise solutions, I sense you are learning functional programming, so I think its best to do stuff like this with recursive function rather than use some magic library function. I notice in your question you ARE using a recusive function, but also an index into an array, lists and recursive function work much more easily than arrays, so if you use recursion the solution is usually simpler if its a list.
I'd also avoid using a string builder, assuming you are learning fp, string builders are imperative, and whilst they obviously work, they wont help you get your head around using immutable data.
The key then is to use the pattern match to match the scenario that you want to use to trigger the upper/lower case logic, as it depends on 2 consecutive characters.
I THINK you want this to happen for the 1st char, and after a '.'?
(I've inserted a '.' as the 1st char to allow the recursive function to just process the '.' scenario, rather than making a special case).
let convertToCamelCase (value : string) =
let rec convertListToCamelCase (value : char list) =
match value with
| [] -> []
| '.' :: second :: rest ->
'.' :: convertListToCamelCase (Char.ToLower second :: rest)
| c :: rest ->
c :: convertListToCamelCase rest
// put a '.' on the front to simplify the logic (and take it off after)
let convertAsList = convertListToCamelCase ('.' :: (value.ToCharArray() |> Array.toList))
String ((convertAsList |> List.toArray).[1..])
The piece to worry about is the recusive piece, the rest of it is just flipping an array to a list and back again.

How to specify last character in 1 cell ( Inside IF )

i have a code that copies and rewrites anything thats between "(" and ")", but now i have different type of data which do not end with ")" so, i need it to stop when it reaches the last character in cell. Maybe it is dumb question but i cant seem to find how to fix my problem. I am a student and total newbie in vba (5 days ago i didn't know what vba is...) also sorry for my bad english.
I've tried to search (in here, google, youtube) but i couldnt find anything i need
'zaciatok=start koniec=end dlzka=length
Do While Mid(LookInHere, y, 1) <> ""
If Mid(LookInHere, Z, 1) = "(" Then
zaciatok = Z
End If
If Mid(LookInHere, y, 1) = ")" Then
koniec = y
dlzka = (koniec - 1) - zaciatok
dlzka = Abs(dlzka)
SplitCatcher = Mid(LookInHere, zaciatok + 1, CStr(dlzka))
MsgBox SplitCatcher
End If
y = y + 1
Z = Z + 1
Loop
In your specific implementation, one option is to modify your Do While ... loop to also test against the length of the string. That line would look something like:
Do While Mid(LookInHere, y, 1) <> "" And y < Len(LookInHere)
That modification tells the statement that it should terminate the loop when the iterating variable y goes past the length of the statement.
Another option is to change it from a Do While loop to a For loop. It would read something like:
For i = 1 to Len(LookInHere)
MsgBox Mid(LookInHere, i, 1)
'Input your logic here
Next i
The problem is that each of these versions is relatively inefficient, looping through each letter in a string a performing a calculation. Consider using built-in Excel functions. The Instr returns the position of a character, or a zero if it is not found. As an example, Instr("Abcdef", "b") would return the number 2, and Instr("Abcdef", "k") would return zero. You can replace the entire loop with these two function calls.
Z = Instr(LookInHere, "(")
y = Instr(LookInHere, ")")
If y = 0 Then y = Len(LookInHere)
Final note: if your patterns begin to get more and more complex, consider reviewing and implementing regular expressions.
You can use Right(LookInHere, 1) to get the last character of LookInHere

How to count the recursion times in Haskell?

I am trying to write a function, given two dates, calculates the distance (in days) between the two dates, using recursion. The function dateDistance takes two dates and uses nextDate to find the next valid date. goodDate makes sure its a valid date.
I am trying to get the result by counting recursions and returning the count. Each time the recursion happens the count variable n should increase and at the end of the recursion when it reaches the end condition (fy == sy && fm == sm && sd == fd) = n it shall return the n.
leapYear x = if ((x `mod` 4) == 0) && ((x `mod` 100) /= 0) || ((x `mod` 400) == 0)
then True
else False
goodDate (y,m,d)
| (d<1 || m>12 || m<1 || y==0) = False
| m `elem` [1,3,5,7,8,10,12] = d<32
| m `elem` [4,6,9,11] = d<31
| leapYear y = d<30
| otherwise= d<29
nextDate (y,m,d) =
if goodDate(y,m,(d+1))
then (y,m,(d+1))
else if goodDate(y,(m+1),1)
then (y,(m+1),1)
else ((y+1),1,1)
dateDistance (fy,fm,fd) (sy,sm,sd)
|(fy == sy && fm == sm && sd == fd) = n
|otherwise = dateDistance nextDate (fy,fm,fd) (sy,sm,sd)
where n = 0
Actually, you don't need to remember it, even though you could do so, by passing it from call to call as an argument.
Let's answer two questions:
What is the base case of your recursion?
Exactly, when both dates are equal; the distance is 0 then.
What is one recursion step?
Well, if the dates f and s are not equal, we search for the nextDate (rather next-day!), lets call it f1. f1 is one day distant from f, but one day nearer to s. f2 ( = nextDate f1) is two days from f, but even nearer to s. So: dateDistance f s = 1 + dateDistance f1 s and dateDistance f1 s = 1 + dateDistance f2 s.
You need to pass the "n" explicitly through the recursive calls. Make it an extra parameter of your dateDistance function and put n+1 in the recursive call. Then call it with an initial value of 0.
You can rename the dateDistance function to something else and rewrite dateDistance to call it with the initial value of 0.

Fortran: Set operations

Fortran: There are two large arrays of integers, the goal is to find out if they have any number in common or not, how?
You may consider that both are in the same size (case 1) or in different sizes (case 2). It is possible also that they have many common numbers repeated, so this should be handled to avoid unnecessary search or operators.
The simplest way is to do Brute-Force search which is not appropriate. We are thinking about SET operations similar to Python as the following:
a = set([integers])
b = set([integers])
incommon = len(a.intersection(b)) > 0 #True if so, otherwise False
So for example:
a = [1,2,3,4,5]
b = [0,6,7,8,9]
sa = set(a)
sb = set(b)
incommon = len(sa.intersection(sb)) > 0
>>> incommon: False
b = [0,6,7,8,1]
incommon = len(sa.intersection(sb)) > 0
>>> incommon: True
How to implement this in Fortran? note that arrays are of large size (>10000) and the operation would repeat for million times!
Updates:
[regarding the comment for the question] We absolutely have tried many ways that we knew. As mentioned BFS method, for example. It works but is not efficient for two reasons: 1) the nature of the method which requires large iterations, 2) the code we could implement. The accepted answer (by yamajun) was very informative to us much more than the question itself. How easy implementation of Quick-Sort, Shrink and Isin all are very nicely thought and elegantly implemented. Our appreciation goes for such prompt and perfect solution.
Maybe this will work.
added from here
The main idea is using intrinsic function ANY().
ANY(x(:) == y) returns .true. if a scalar value y exists in an array x. When y is also an array ANY(x == y) returns x(1)==y(1) & x(2)==y(2) &..., so we have to use do loop for each element of y.
Now we try to delete duplicate numbers in the arrays.
First we sort the arrays. Quick-sort can be written concisely in a Haskell-like manner.
(Reference : Arjen Markus, ACM Fortran Forum 27 (2008) 2-5.)
But because recursion consumes stacks, Shell-sort might be a better choice, which does not require extra memories. It is often stated in textbooks that Shell-sort works in O(N^3/2~5/4), but it works much faster using special gap functions.wikipedia
Next we delete duplicate numbers by comparing successive elements using the idea of zip pairs. [x(2)/=x(1), ..., x(n)/=x(n-1)] We need to add extra one element to match array size. The intrinsic function PACK() is used as a Filter.
to here
program SetAny
implicit none
integer, allocatable :: ia(:), ib(:)
! fortran2008
! allocate(ia, source = [1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5])
! allocate(ib, source = [0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9])
allocate(ia(size([1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5])))
allocate(ib(size([0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9])))
ia = [1,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5,2,3,4,5]
ib = [0,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9,6,7,8,9]
print *, isin( shrnk( ia ), shrnk( ib ) )
stop
contains
logical pure function isin(ia, ib)
integer, intent(in) :: ia(:), ib(:)
integer :: i
isin = .true.
do i = 1, size(ib)
if ( any(ia == ib(i)) ) return
end do
isin = .false.
return
end function isin
pure function shrnk(ia) result(res)
integer, intent(in) :: ia(:)
integer, allocatable :: res(:) ! f2003
integer :: iwk(size(ia))
iwk = qsort(ia)
res = pack(iwk, [.true., iwk(2:) /= iwk(1:)]) ! f2003
return
end function shrnk
pure recursive function qsort(ia) result(res)
integer, intent(in) :: ia(:)
integer :: res(size(ia))
if (size(ia) .lt. 2) then
res = ia
else
res = [ qsort( pack(ia(2:), ia(2:) &lt ia(1)) ), ia(1), qsort( pack(ia(2:), ia(2:) &gt= ia(1)) ) ]
end if
return
end function qsort
end program SetAny
Shell sort
pure function ssort(ix) ! Shell Sort
integer, intent(in) :: ix(:)
integer, allocatable :: ssort(:)
integer :: i, j, k, kmax, igap, itmp
ssort = ix
kmax = 0
do ! Tokuda's gap sequence ; h_k=Ceiling( (9(9/4)^k-4)/5 ), h_k &lt 4N/9 ; O(N)~NlogN
if ( ceiling( (9.0 * (9.0 / 4.0)**(kmax + 1) - 4.0) / 5.0 ) &gt size(ix) * 4.0 / 9.0 ) exit
kmax = kmax + 1
end do
do k = kmax, 0, -1
igap = ceiling( (9.0 * (9.0 / 4.0)**k - 4.0) / 5.0 )
do i = igap, size(ix)
do j = i - igap, 1, -igap
if ( ssort(j) &lt= ssort(j + igap) ) exit
itmp = ssort(j)
ssort(j) = ssort(j + igap)
ssort(j + igap) = itmp
end do
end do
end do
return
end function ssort

Making a string concatenation operator in R

I was wondering how one might go about writing a string concatenation operator in R, something like || in SAS, + in Java/C# or & in Visual Basic.
The easiest way would be to create a special operator using %, like
`%+%` <- function(a, b) paste(a, b, sep="")
but this leads to lots of ugly %'s in the code.
I noticed that + is defined in the Ops group, and you can write S4 methods for that group, so perhaps something like that would be the way to go. However, I have no experience with S4 language features at all. How would I modify the above function to use S4?
As others have mentioned, you cannot override the sealed S4 method "+". However, you do not need to define a new class in order to define an addition function for strings; this is not ideal since it forces you to convert the class of strings and thus leading to more ugly code. Instead, one can simply overwrite the "+" function:
"+" = function(x,y) {
if(is.character(x) || is.character(y)) {
return(paste(x , y, sep=""))
} else {
.Primitive("+")(x,y)
}
}
Then the following should all work as expected:
1 + 4
1:10 + 4
"Help" + "Me"
This solution feels a bit like a hack, since you are no longer using formal methods but its the only way to get the exact behavior you wanted.
I'll try this (relatively more clean S3 solution)
`+` <- function (e1, e2) UseMethod("+")
`+.default` <- function (e1, e2) .Primitive("+")(e1, e2)
`+.character` <- function(e1, e2)
if(length(e1) == length(e2)) {
paste(e1, e2, sep = '')
} else stop('String Vectors of Different Lengths')
Code above will change + to a generic, and set the +.default to the original +, then add new method +.character to +
You can also use S3 classes for this:
String <- function(x) {
class(x) <- c("String", class(x))
x
}
"+.String" <- function(x,...) {
x <- paste(x, paste(..., sep="", collapse=""), sep="", collapse="")
String(x)
}
print.String <- function(x, ...) cat(x)
x <- "The quick brown "
y <- "fox jumped over "
z <- "the lazy dog"
String(x) + y + z
If R would thoroghlly comply with S4, the following would have been enough:
setMethod("+",
signature(e1 = "character", e2 = "character"),
function (e1, e2) {
paste(e1, e2, sep = "")
})
But this gives an error that the method is sealed :((. Hopefully this will change in the feature versions of R.
The best you can do is to define new class "string" which would behave exactly as "character" class:
setClass("string", contains="character")
string <- function(obj) new("string", as.character(obj))
and define the most general method which R allows:
setMethod("+", signature(e1 = "character", e2 = "ANY"),
function (e1, e2) string(paste(e1, as.character(e2), sep = "")))
now try:
tt <- string(44444)
tt
#An object of class "string"
#[1] "44444"
tt + 3434
#[1] "444443434"
"sfds" + tt
#[1] "sfds44444"
tt + tt
#[1] "4444444444"
343 + tt
#Error in 343 + tt : non-numeric argument to binary operator
"sdfs" + tt + "dfsd"
#An object of class "string"
#[1] "sdfs44444dfsd"
You have given yourself the correct answer -- everything in R is a function, and you cannot define new operators. So %+% is as good as it gets.

Resources