I need to check if a particular string is one of a set of predetermined strings.
Two methods to do it came to my mind: setting up a table to return true on a particular value
local isParticular = {
[string1] = true,
[string2] = true
}
print(isParticular[string1]) -- true
print(isParticular[randomString]) -- nil -> false
Or setting a function to check it with a conditional determination
function isParticular(s)
return s == string1 or s == string2
end
print(isParticular(string1)) -- true
print(isParticular(randomString)) -- false
From what I understand the table method would take the same time for both any of the particular strings and for different strings, while the function call because of short-circuit evaluation will take less time for string1 and more time for string2 and randomString.
Also, both the function call and the table access are known for causing a little overhead, but maybe the short-circuit evaluation can make the difference (in being slower I think, especially considered I have more than 2 particular strings and that most of the times the string won't match any of them).
So what method should I use?
A hash-table lookup would outperform your functional lookup for a large dataset. So, go with the first method:
local isParticular = {
string1 = true,
string2 = true
}
print(isParticular[string1]) -- true
print(isParticular[randomString]) -- nil -> false
Related
I want to fully understand the different between compareTo and equals.
I have used this code while trying to understand the difference between them:
println("${'A'.compareTo('b')}")
println("${'A'.equals('b')}")
While using compareTo I get -1 as a result. Nothing is wrong here.
It is also mentioned in the documentation that I will get -1 as a result if the strings are not the same:
Compares this object with the specified object for order. Returns zero if this object is equal to the specified other object, a negative number if it's less than other, or a positive number if it's greater than other.
And while using equals the result that I got was false, then again it looks good as the documentation mentioned - this method will return a boolean:
Indicates whether some other object is "equal to" this one.
Maybe I am missing something really simple, but in the described case, what is the difference between those methods (other than the value that is coming from compareTo and equals)?
The difference between equals and compareTo comes from a few sources.
First, equals is inherited from the Any type in Kotlin, so it is a method attached to all values in the language.
compareTo is inherited from the Comparable type, specifically meaning only its inheritors of:
Boolean, Byte, Char, Double, Duration, Enum, Float, Int etc...
will have the method.
Second, the signature of returned value is different.
Equals has a return of Boolean, meaning you only have true or false being returned from the method call. This will only tell you directly if they are the same or not, with no extra information
The compareTo method has a return of Int, which is a magnitude of the difference between the comparison of the input type. The comparison can not be between different types.
The return of a positive Integer that the Receiver value, is greater than the input value being checked against
To clarify, the Receiver is the variable or instance that the compareTo method is being called on.
For example:
val myValue: Boolean = false
val myCheck: Boolean = true
myValue.compareTo(myCheck) // Return: 1
In that code, the Receiver would be myValue because it is calling the method compareTo. Kotlin interprets true to be a greater value than false so myValue.compareTo(myCheck) will return1`
The return of 0 means that the Receiver value is the same value as the input parameter value.
val myValue: Boolean = true
val otherValue: Boolean = true
myValue.compareTo(otherValue) // Return: 0
The return of a negative number is a magnitude of difference between the two values, specific to each type based on the Receiver value being considered a value of less than the input parameter.
val myString = "zza"
val otherString = "zzz"
myString.compareTo(otherString) // Return: -25
The equality being a bit complicated to explain, but being the same length with only 1 Char place being different, it returns the difference of the Char values as an Int.
val myString = "zz"
val otherString = "zzz"
myString.compareTo(otherString) // Return: -1
In this case the difference is literally the existence of 1 Char, and does not have a value difference to assign.
For equals, the comparative other can be of Any type, not specifically the same type as the Receiver like in compareTo.
The equals method is also an operator function and can be syntactically used such as:
val myString: String = "Hello World"
val otherString: String = "Hello World"
myString == otherString // Return: true
Any non-null value can not be equal to null:
val myString = "Hello World"
val maybeNull: String? = null
myString == maybeNull // Return: false
Equality is specific to each type and has it's own specific documentation to clarify its nuances: Kotlin Equality
I am new to elixir, having hard time with updating the variables. Need some help. I have two Maps
firstMsg = %{msg: "Hello", vt: %{"p1" => 1, "p2" => 1, "p3" => 1}, from: "p3"}
state = %{ :name => "p2",
vector: %{"p1" => 0, "p2" => 0, "p3" => 0},
participants: ["p1","p3","p2"]
}
I am passing these two maps in a function, which should return me either true or false, depending on some conditions.
defmodule Testfunc do
def keep_in_pending(firstMsg, state) do
if (firstMsg.vt[firstMsg.from] == state.vector[firstMsg.from] + 1) do
#IO.puts("Origin proc clock is 1 step ahead from rcvd process Origin clk")
checking = false #initially set this to false
for n <- state.participants do
if n != firstMsg.from do #filter the origin processes
IO.puts("#{n}: #{inspect firstMsg.vt[n]} <= #{n}: #{inspect state.vector[n]} ")
checking = cond do
(firstMsg.vt[n] <= state.vector[n]) -> false
(firstMsg.vt[n] > state.vector[n]) -> true
end
end
end
end
checking
end
end
out = Testfunc.keep_in_pending(firstMsg, state)
IO.puts("#{inspect out}")
It always gives me false (value that I initially assigned to it), and doesn't updates. I think the scope of variable is restricted to the inner "if". Can anyone give me suggestion on how to re arrange this code so that it returns me proper updated boolean value ?
So in this case it should return me true because firstMsg.vt["p1"] > state.vector["p1"].
Welcome to Elixir. You're right, it is a matter of scope, but it runs a bit deeper than that. Elixir is a language where your data is immutable. You can't set checked to false, run a loop, and set it to true somewhere in that loop. That would mutate checked. It's not that someone designed devilish scope rules to prevent this, but rather that the underlying virtual machine doesn't mutate state.
The style of programming where you set some state, then run a procedure that changes that state, relies on mutable state. When state is immutable, the alternative to a loop is instead recursion. You carry new state in every recursive call.
You're learning a functional language, and I think it will be helpful to pull apart your code into a few functions. This will both address your immediate concern, and make your code easier to understand.
def keep_in_pending(%{from: from, vt: vt}, %{vector: vector, participants: ps}) do
if vt[from] == vector[from] + 1 do
ps
|> Enum.reject(& &1 == from)
|> check_participants(vector, vt, false)
end
end
def check_participants([], _, _, bool), do: bool
def check_participants([h | t], vector, vt, bool) do
check_participants(t, vector, vt, vt[h] > vector[h])
end
I'll briefly explain it.
First, note that I've pattern matched the inputs, to pull out the interesting parts we're using in the function body. This gets rid of some of the repetitive firstMsg.from business. (Btw, snake_case your variable names.)
Second, I haven't touched the gnarly outer if-condition. I simply don't know what it means. You should perhaps extract it and give it an intention revealing name.
The real action begins when we pipe participants. You were filtering inside your list comprehension. I've filtered with Enum.reject/1 instead. Then we pipe the list into a recursive function. It's going to carry the boolean through to the end, starting off with false. It needs to check values in vt and vector, so they're also passed in.
The first rule of recursion is the first rule of recursion. No, wait. It's to think about how to terminate the recursion. We're working through a list of participants, so we'll stop when the list is empty. At that point, we have the boolean we're looking for, so just return it.
The recursive step is to pick off an item from the list (h), use it to determine a new boolean (vt[h] > vector[h]) and call the function again with the rest of the list (check_participants(t, ...)).
Hope this helps! Have fun learning functional programming!
So here is an idea: if you are trying to make a function return a boolean, just make it return a boolean, don't assign it to a variable. Assigning inside an if/case/cond will show a warning. Also, you are not reassigning the checking because variables bound inside the comprehension (for) are restricted to that scope. Your best tools in Elixir will be first pattern matching and second the pipe operator, so always try to use them.
Here is an idea to refactor that code:
defmodule Testfunc do
def keep_in_pending(firstMsg, state) do
if (firstMsg.vt[firstMsg.from] == state.vector[firstMsg.from] + 1) do
state.participants
|> Enum.filter(fn (n) -> n != firstMsg.from end)
|> Enum.reduce(fn (n, _) ->
cond do
(firstMsg.vt[n] <= state.vector[n]) -> false
(firstMsg.vt[n] > state.vector[n]) -> true
end
end)
end
end
end
In the code below:
var verticesCount: Int // to read a vertices count for graph
// Reading until we get a valid vertices count.
while (!Assertions.checkEnoughVertices(
verticesCount = consoleReader.readInt(null, Localization.getLocStr("type_int_vertices_count"))))
// The case when we don't have enough vertices.
println(String.format(Localization.getLocStr("no_enough_vertices_in_graph"),
Assertions.CONFIG_MIN_VERTICES_COUNT))
val resultGraph = Graph(verticesCount)
we are getting next error on the last line:
Error:(31, 33) Kotlin: Variable 'verticesCount' must be initialized
Assertions.checkEnoughVertices accepts a safe type variable as an argument (verticesCount: Int), so it's impossible for verticesCount to be uninitialized or null here (and we're getting no corresponding errors on those lines).
What's going on on the last line when already initialized variable becomes uninitialized again?
The syntax you've used denotes a function call with named arguments, not the assignment of a local variable. So verticesCount = is just an explanation to the reader that the value which is being passed here to checkEnoughVertices corresponds to the parameter of that function named verticesCount. It has nothing to do with the local variable named verticesCount declared just above, so the compiler thinks you've still to initialize that variable.
In Kotlin, the assignment to a variable (a = b) is not an expression, so it cannot be used as a value in other expressions. You have to split the assignment and the while-loop condition to achieve what you want. I'd do this with an infinite loop + a condition inside:
var verticesCount: Int
while (true) {
verticesCount = consoleReader.readInt(...)
if (Assertions.checkEnoughVertices(verticesCount)) break
...
}
val resultGraph = Graph(verticesCount)
Well, technically it is possible to assign values to variables in the while condition - and anything else you might want to do there, too.
The magic comes from the also function:
Try this: (excuse the completely useless thing this is doing...)
var i = 10
var doubleI: Int
while ((i * 2).also { doubleI = it } > 0) {
i--
println(doubleI)
}
Any expression can be "extended" with "something to do" by calling also which takes the expression it is called upon as the it parameter and executes the given block. The value also returns is identical to its caller value.
Here's a very good article to explain this and much more: https://medium.com/#elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84
I have a total of 6 booleans and the only thing separating them is a number. They're named checker0 though 5.
So checker0, checker1, checker2, checker3, checker4 and checker5.
All of these grants or denies access to certain parts of the app wether the bool is true or false.
I then have a randomiser using:
randomQuestionNumber = arc4random_uniform(5);
So say we get number 3, checker3 = true;
But my question now is would it be possible to set this one to true without having to go thru if statements.
My idea was to implement the way you print a int to say the NSLog using the %d.
NSLog(#"The number is: %d", randomQuestionNumber);
So something like:
checker%d, randomQuestionNumber = true.
Would something like that be possible? So i won't have to do like this:
if (randomQuestionNumber == 0) {
checker0 = true;
}
else if (randomQuestionNumber == 1)
{
checker1 = true;
}
Thanks you very much! :)
Every time you find yourself in a situation when you name three or more variables checkerN you know with a high degree of probability that you've missed a place in code where you should have declared an array. This becomes especially apparent when you need to choose one of N based on an integer index.
The best solution would be to change the declaration to checker[6], and using an index instead of changing the name. If this is not possible for some reason, you could still make an array of pointers, and use it to make modifications to your values, like this:
BOOL *ptrChecker[] = {&checker0, &checker1, &checker2, ...};
...
*ptrChecker[randomQuestionNumber] = true;
I found a comment today in a source file:
// - no longer compare BOOL against YES (dangerous!)
Is comparing BOOL against YES in Objective-C really that dangerous? And why is that?
Can the value of YES change during runtime? Maybe NO is always 0 but YES can be 1, 2 or 3 - depending on runtime, compiler, your linked frameworks?
The problem is that BOOL is not a native type, but a typedef:
typedef signed char BOOL;
#define YES (BOOL)1
#define NO (BOOL)0
As a char, its values aren't constrained to TRUE and FALSE. What happens with another value?
BOOL b = 42;
if (b)
{
// true
}
if (b != YES)
{
// also true
}
You should never compare booleans against anything in any of the C based languages. The right way to do it is to use either:
if (b)
or:
if (!b)
This makes your code much more readable (especially if you're using intelligently named variables and functions like isPrime(n) or childThreadHasFinished) and safe. The reason something like:
if (b == TRUE)
is not so safe is that there are actually a large number of values of b which will evaluate to true, and TRUE is only one of them.
Consider the following:
#define FALSE 0
#define TRUE 1
int flag = 7;
if (flag) printf ("number 1\n");
if (flag == TRUE) printf ("number 2\n");
You should get both those lines printed out if it were working as expected but you only get the first. That's because 7 is actually true if treated correctly (0 is false, everything else is true) but the explicit test for equality evaluates to false.
Update:
In response to your comment that you thought there'd be more to it than coder stupidity: yes, there is (but I still wouldn't discount coder stupidity as a good enough reason - defensive programming is always a good idea).
I also mentioned readability, which is rather high on my list of desirable features in code.
A condition should either be a comparison between objects or a flag (including boolean return values):
if (a == b) ...
if (c > d) ...
if (strcmp (e, "Urk") == 0) ...
if (isFinished) ...
if (userPressedEsc (ch)) ...
If you use (what I consider) an abomination like:
if (isFinished == TRUE) ...
where do you stop:
if (isFinished == TRUE) ...
if ((isFinished == TRUE) == TRUE) ...
if (((isFinished == TRUE) == TRUE) == TRUE) ...
and so on.
The right way to do it for readability is to just use appropriately named flag variables.
All this is true, but there are valid counter arguments that might be considered:
— Maybe we want to check a BOOL is actually YES or NO. Really, storing any other value than 0 or 1 in a BOOL is pretty incorrect. If it happens, isn't it more likely because of a bug somewhere else in the codebase, and isn't not explicitly checking against YES just masking this bug? I think this is way more likely than a sloppy programmer using BOOL in a non-standard way. So, I think I'd want my tests to fail if my BOOL isn't YES when I'm looking for truth.
— I don't necessarily agree that "if (isWhatever)" is more readable especially when evaluating long, but otherwise readable, function calls,
e.g. compare
if ([myObj doThisBigThingWithName:#"Name" andDate:[NSDate now]]) {}
with:
if (![myObj doThisBigThingWithName:#"Name" andDate:[NSDate now]]) {}
The first is comparing against true, the second against false and it's hard to tell the difference when quickly reading code, right?
Compare this to:
if ([myObj doThisBigThingWithName:#"Name" andDate:[NSDate now]] == YES) {}
and
if ([myObj doThisBigThingWithName:#"Name" andDate:[NSDate now]] == NO) {}
…and isn't it much more readable?
Again, I'm not saying one way is correct and the other's wrong, but there are some counterpoints.
When the code uses a BOOL variable, it is supposed to use such variable as a boolean. The compiler doesn't check if a BOOL variable gets a different value, in the same way the compiler doesn't check if you initialize a variable passed to a method with a value taken between a set of constants.