Why can I invoke a fun without passing parameter name in Kotlin? - android

There are 4 parameters with default value in function joinToString, in my mind, I should pass parameter value by order when I omit parameter name.
So I think the Code println(letters.joinToString( transform={ it.toLowerCase() } ) ) is right.
But in fact the Code println(letters.joinToString { it.toLowerCase() } ) is right too, why?
fun <T> Collection<T>.joinToString(
separator: String = ", ",
prefix: String = "",
postfix: String = "",
transform: (T) -> String = { it.toString() }
): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) {
if (index > 0) result.append(separator)
result.append(transform(element))
}
result.append(postfix)
return result.toString()
}
fun main(args: Array<String>) {
val letters = listOf("Alpha", "Beta")
println(letters.joinToString { it.toLowerCase() } ) //It's Ok
println(letters.joinToString( transform={ it.toLowerCase() } ) ) //It's OK
}

Because you're using a different syntax.
If the last param of a method is a method reference then you can omit the parenthesis and just pass in the function with the { brackets.
it in this case becomes T that you were passing into the function
println(letters.joinToString { it.toLowerCase() } )
Below is what you thought you were entering. This wouldn't compile and would require the named argument or for the params to be in the right order. You would also have to change the syntax from using it to using the regular functional syntax
println(letters.joinToString(it.toLowerCase()))

In addition to #Dan's answer, you don't need to provide a named argument, but if you do so then you're forced to use the named argument for all the following arguments (from the documentation: "all the positional arguments should be placed before the first named one"). In your case the only named argument you're providing is the last one, and all other arguments have default values so you're not forced to provide them, as long as the default value is fine for you.

Related

I use proper way to compare two strings but still the program is malfunctioning [duplicate]

I'm studying kotlin, but I'm very disappointed, I can not compare two Strings.
What is the right way to compare.
btn_login.setOnClickListener {
val login = input_email.text.trim()
val pass = input_password.text.trim()
if( login.equals( pass ) ){
startActivity<MainActivity>()
}
if (login?.equals(other = pass)){
startActivity<MainActivity>()
}
if (login == pass){
startActivity<MainActivity>()
}
}
According to documentation for structual equality use ==. It is translated to a?.equals(b) ?: (b === null).
In you case convert login and pass from SpannableStringBuilder to String.
val login = input_email.text.trim().toString()
Here is the example for matching the two strings using kotlin.
If you are using == (double equals) for matching the string then it's compare the address & return maximum time wrong result as per java documentation so use equals for the same
If you want to use equal ignore case then pass the true in the equals method of String
if (s1.equals(s2,true))
other wise you can just use this without boolean like
if (s1.equals(s2,false)) or if (s1.equals(s2))
compleate code is below
fun main(args: Array<String>) {
val s1 = "abc"
val s2 = "Abc"
if (s1.equals(s2,true))
{
println("Equal")
}
else
{
println("Not Equal")
}
}
Covert both the SpannableStringBuilder to string with toString, this should work.
val login = input_email.text.trim().toString()
val pass = input_password.text.trim().toString()
if (login == pass){
startActivity<MainActivity>()
}
1. == :
if ( string1 == string2 ){...}
2. equals :
Indicates whether some other object is "equal to" this one.
Implementations must fulfil the following requirements:
Reflexive: for any non-null reference value x, x.equals(x) should
return true.
Symmetric: for any non-null reference values x and y, x.equals(y)
should return true if and only if y.equals(x) returns true.
Transitive: for any non-null reference values x, y, and z, if
x.equals(y) returns true and y.equals(z) returns true, then
x.equals(z) should return true
Consistent: for any non-null reference values x and y, multiple
invocations of x.equals(y) consistently return true or consistently
return false, provided no information used in equals comparisons on
the objects is modified.
/** * Returns `true` if this string is equal to [other], optionally ignoring character case. * * #param ignoreCase `true` to ignore character case when comparing strings. By default `false`. */
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
3. compareTo :
public override fun compareTo(other: String): Int
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.
public fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
Compares two strings lexicographically, optionally ignoring case
differences
i know this is way too late, but as a newbie learning Kotlin, i had the same doubts.
then i came across this wonderful article that articulates the various string comparison types in Kotlin and the differences between them all.
in short both == and .equals() can be used to compare the value of 2 strings in kotlin.
hopefully that helps
With case checking
String a=.....
String b=.....
if(a==b){
}
IgnoreCase
if(a.equals(b,false))
KOTLIN:
if (editText1.text.toString() == editText2.text.toString() ) {
println("Should work now! The same value")
}
Try the following solution, see if it helps:
val passStr: String = textView.text.toString()
if( loginStr.compareTo(passStr, false) ){
startActivity<MainActivity>()
}
Try this surely will work.
val style = buildString { karthik}
val style2 = buildString { karthik }
var result = style.equals(style2)
if(result){//Do something}

How To Return Nested Variable?

I don't know how to RETURN variable from the following function.
Here is the code...
downloadData.setOnClickListener {
val handler = Handler(Looper.getMainLooper())
handler.post {
val fetchData =
FetchData("http://localhost/xampp/CRM/PHP/show_contacts_db.php")
if (fetchData.startFetch()) {
if (fetchData.onComplete()) {
val result = fetchData.data.toString()
Log.i("FetchData", result)
val companyName = result.substringAfter("Name: ").substringBefore(";")
showContactName.text = "${companyName}"
val companyNumber = result.substringAfter("Number: ").substringBefore(";")
showContactNumber.text = "${companyNumber}"
}
}
}
}
companyName and companyNumber needed to be returned so I can use it in other places.
When I Try to use Return companyNumber I have a message that "return" is not allowed here.
Generally with lambdas, you don't explicitly return a value - the lambda returns the value of the last expression. Using your code as an example (it won't actually work but we'll get to that!):
handler.post {
...
companyNumber
}
which is the same as how things like map calls take a transformation function
listOf(1, 2, 3).map { it * 2 }
that's just doubling each number, but the result is being implicitly returned and stored in the resulting list, right? And it lets you chain lambdas together, since each one evaluates to a value (which might be Unit if it "doesn't return a result")
If you want, you can explicitly use what's called a qualified return:
handler.post {
...
return#post companyNumber
}
where you're naming the function call you're returning to.
Kotlin docs: returning a value from a lambda expression
Also if you want to return two values, you can't do that - so you'll have to bundle them up in a single object. You could just return a Pair, or create a data class that's more readable:
return#post Pair(companyName, companyNumber)
//or
data class CompanyDeets(val name: String, val number: String)
...
return#post CompanyDeets(companyName, companyNumber)
But aside from how you do it in general, why do you want to return anything here? Handler#post takes a Runnable which returns nothing (void in Java), and View.OnClickListener#onClick doesn't return anything either.
Neither of them would do anything with a value you returned - and if you explicitly return a value, that means your lambda's signature doesn't match (right now it's implicitly returning Unit to match what's expected by the caller), and you'll get an error
What you probably want to do instead, is create a function inside your class (Activity or whatever) that uses your data, something like fun doSomethingWith(companyName: String, companyNumber: String) and call that inside your lambda. That's way you're executing code in reaction to a click
just declare var Company Name in global, or create a function with that params
var companyName: String? = null
handler.post {
...
companyName = result.substringAfter("Name: ").substringBefore(";")
}
OR
handler.post {
...
save(result.substringAfter("Name: ").substringBefore(";"))
}
fun save(companyName: String){ ... }

get the value of a parameter from a data class in kotlin

So, i'm pretty new to kotlin and still learning stuff, I have a data class named Country with 4 parameters
County(name:String, policePhone:String, ambulancePhone:String,
firebrigadePhone:String)
, a listOf Country with 27 objects in it and a var nameC1 taken from the MainActivity.
I've called the list method forEach and I want to confront every name in the list with the variable nameC and when a match is found execute some code.
data class Country(val name: String, val police:String, val ambulance:String,val firefighter:String) {
}
var nameC1 = (activity as MainActivity).nameC
val numberList= listOf<Country>(
Country("Austria","133","144","122"),
Country("Belgium","101","100","100"),
Country("Bulgaria","166","150","160"),
Country("Croatia","192","194","193"),
Country("Cyprus","199","199","199"),
Country("Czech Republic","158","155","150"),
Country("Denmark","112","112","112"),
Country("Estonia","112","112","112"),
Country("Finland","112","112","112"),
Country("France","17","15","18"),
Country("Germany","110","112","112"),
Country("Greece","100","166","199"),
Country("Hungary","107","104","105"),
Country("Ireland","112","112","112"),
Country("Italy","113","118","115"),
Country("Latvia","112","112","112"),
Country("Lithuania","02","03","01"),
Country("Luxembourg","113","112","112"),
Country("Malta","112","112","112"),
Country("Netherlands","112","112","112"),
Country("Poland","997","999","998"),
Country("Portugal","112","112","112"),
Country("Romania","112","112","112"),
Country("Slovakia","158","155","150"),
Country("Slovenia","113","112","112"),
Country("Spain","092","061","080"),
Country("Sweden","112","112","112")
)
numberList.forEach { if (Country.name==nameC1 ) }
// i'm expecting String1==String2 but i'm
//stuck here because it says name is an unresolved reference
}
I'd use a getName() but i know in kotlin getter/setter are automated ( I'm not used to it) and ihaven't found anything useful on the kotlin doc. site,
I've seen on this site that someone suggested to implement Kotlin-reflection but I don't understand how I'm not supposed to get a parameter from a class by default.
forEach creates a lambda for each of the element in the collection. The default name for the element inside the lambda is it. But you can rename it to something else too. Refer to the doc
Here is a working example of your code
data class Country(val name: String, val police:String, val ambulance:String,val firefighter:String)
fun doThis(nameC1: String) {
val numberList= listOf<Country>(
Country("Austria","133","144","122"),
Country("Belgium","101","100","100"),
Country("Bulgaria","166","150","160"),
Country("Croatia","192","194","193"),
Country("Cyprus","199","199","199"),
Country("Czech Republic","158","155","150"),
Country("Denmark","112","112","112"),
Country("Estonia","112","112","112"),
Country("Finland","112","112","112"),
Country("France","17","15","18"),
Country("Germany","110","112","112"),
Country("Greece","100","166","199"),
Country("Hungary","107","104","105"),
Country("Ireland","112","112","112"),
Country("Italy","113","118","115"),
Country("Latvia","112","112","112"),
Country("Lithuania","02","03","01"),
Country("Luxembourg","113","112","112"),
Country("Malta","112","112","112"),
Country("Netherlands","112","112","112"),
Country("Poland","997","999","998"),
Country("Portugal","112","112","112"),
Country("Romania","112","112","112"),
Country("Slovakia","158","155","150"),
Country("Slovenia","113","112","112"),
Country("Spain","092","061","080"),
Country("Sweden","112","112","112") )
numberList.forEach {
if (it.name == nameC1) {
println("Match")
}
}
}
fun main() {
doThis("Slovenia")
}
Try it for yourself on play.kotlinlang.org - Link
The above code will execute the println function when the condition is true.
In the forEach loop you have to use it to access the name parameter.
like this
numberList.forEach { if (it.name==nameC1 )}
Try with the following code. You can apply filter on list
//if you want iterate your list try with below code
numberList.forEach {
val name = it.name
val police = it.police
}
//If you want apply filter on list take reference from below code
private var countryList: ArrayList<Country> = arrayListOf(
Country("Austria", "133", "144", "122"),
Country("Belgium", "101", "100", "100")
)
val searchList = countryList.filter { country-> country.name == nameC1}

Kotlin: How can I reduce child arrays into a single array?

I have a pice of code in Swift that reduces a list of TVSchedule objects into an array of TVMatch pobjects. Each TVSchedule, has a property called events, that is a list of TVMatches.
The code in swift is the following:
var matches: [TVMatch] {
let slots = timeSlots.reduce(into: [TVMatch]()) { (result, schedule) in
result.append(contentsOf: schedule.events)
}
return slots
}
I'm trying to do the same reduce in Kotlin and the code I have is the following:
val matches: ArrayList<TVMatch>
get() {
val slots = timeSlots.fold(arrayListOf<TVMatch>()) { result, schedule ->
result.addAll(schedule.events)
}
return slots
}
However, the Kotlin code gives me a type error, and does not compile. What is the problem here?
addAll returns a boolean, but the return value of the fold-operation should be of same type as the given initial object (in this case ArrayList).
You can solve that one easily by just adding result after your addAll-statement, e.g.:
result.addAll(schedule.events)
result // this is now the actual return value of the fold-operation
Alternatively just use apply or similar instead:
result.apply {
addAll(schedule.events)
} // result is the return value then
Note that you can actually simplify altogether using flatMap to just (side-note: if you use this approach the matches are evaluated only once of course, but flatMap is the star here anyway ;-))):
val matches = timeSlots.flatMap { it.events } // this is a new list! (note, if you do several mappings in a row, you may want to use timeSlots.asSequence().flatMap { }.map { }.toList() / or .toMutableList() instead
Alternatively if you really require the matches to be of type ArrayList, use flatMapTo instead:
val matches = timeSlots.flatMapTo(ArrayList()) { it.events }
You can of course keep the get() if you must, or just move the getting of the matches to its own function, e.g.:
fun getMatches() = timeSlots.flatMapTo(ArrayList()) { it.events }
Am I crazy, or can't you just replace the code with
val matches: List<TVMatch>
get() = timeSlots.flatMap { schedule -> schedule.events }
?

How to understand the fun buildString(builderAction: (StringBuilder) -> Unit) : String in Kotlin?

The following code is from https://github.com/gbaldeck/learning-kotlin/blob/master/src/main/kotlin/org/learning/DSLconstruction.kt
I find it hard to understand.
1: The fun buildString only accept one lambda parameter in Section A, why are there two parameters passed in Section B?
2: What is full code of Section B?
Such as
val s = buildString { aa : StringBuild -> aa.append("Hello.") } // I don't know whether it's right?
3: What is this it in Section B? Does this it represent StringBuild ?
Section A
fun buildString(builderAction: (StringBuilder) -> Unit ) : String {
val sb = StringBuilder()
builderAction(sb)
return sb.toString()
}
Section B
val s = buildString {
it.append("Hello, ")
it.append("World!")
}
logError(s) //The result is Hello, World!
1: The fun buildString only accept one lambda parameter in Section A, why are there two parameters passed in Section B?
There is only 1 parameter passed to that function: specifically, the builderAction of type (StringBuilder) -> Unit.
So
val s = buildString {
it.append("Hello, ")
it.append("World!")
}
is equivalent to
val s: String = buildString(builderAction = { stringBuilder: StringBuilder ->
stringBuilder.append("Hello, ")
stringBuilder.append("World!")
// return Unit
})
Meaning it is actually the unnamed single argument of (StringBuilder) -> Unit, so it's a StringBuilder.
Yes, it is the StringBuilder. It is named it by default. You can specify the name if you want to.
buildString {
it.append("...")
}
is the same as
buildString { it ->
it.append("...")
}
or even
buildString { myNewString ->
myNewString.append("...")
}
There is only one parameter being passed in section B, namely, this parameter:
{
it.append("Hello, ")
it.append("World!")
}
That is one lambda expression, not two. The lambda expression has 2 lines, but it's still one lambda.
If you want to expand the call to buildString,
val builder = StringBuilder()
builder.append("Hello, ")
builder.append("World!")
val s = builder.toString()
Yes, the it refers to the StringBuilder sb in buildString. When the function type has only one parameter, you can refer to the single parameter with it in the lambda expression without giving it a name.

Categories

Resources