Kotlin: split string from end - kotlin

I want to split I_have_a_string into I_have_a and string. Is there a built in function to split from end in Kotlin? The following is what I am doing now
val words = myString.split("_")
val first = words.dropLast(1).joinToString("_")
val second = words.last()

Look at this:
val myString = "I_have_a_string"
val first = myString.substringBeforeLast("_")
val second = myString.substringAfterLast("_")
I think its self explanatory

Related

Convert String into list of Pairs: Kotlin

Is there an easier approach to convert an Intellij IDEA environment variable into a list of Tuples?
My environment variable for Intellij is
GROCERY_LIST=[("egg", "dairy"),("chicken", "meat"),("apple", "fruit")]
The environment variable gets accessed into Kotlin file as String.
val g_list = System.getenv("GROCERY_LIST")
Ideally I'd like to iterate over g_list, first element being ("egg", "dairy") and so on.
And then ("egg", "dairy") is a tuple/pair
I have tried to split g_list by comma that's NOT inside quotes i.e
val splitted_list = g_list.split(",(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*\$)".toRegex()).toTypedArray()
this gives me first element as [("egg", second element as "dairy")] and so on.
Also created a data class and tried to map the string into data class using jacksonObjectMapper following this link:
val mapper = jacksonObjectMapper()
val g_list = System.getenv("GROCERY_LIST")
val myList: List<Shopping> = mapper.readValue(g_list)
data class Shopping(val a: String, val b: String)
You can create a regular expression to match all strings in your environmental variable.
Regex::findAll()
Then loop through the strings while creating a list of Shopping objects.
// Raw data set.
val groceryList: String = "[(\"egg\", \"dairy\"),(\"chicken\", \"meat\"),(\"apple\", \"fruit\")]"
// Build regular expression.
val regex = Regex("\"([\\s\\S]+?)\"")
val matchResult = regex.findAll(groceryList)
val iterator = matchResult.iterator()
// Create a List of `Shopping` objects.
var first: String = "";
var second: String = "";
val shoppingList = mutableListOf<Shopping>()
var i = 0;
while (iterator.hasNext()) {
val value = iterator.next().value;
if (i % 2 == 0) {
first = value;
} else {
second = value;
shoppingList.add(Shopping(first, second))
first = ""
second = ""
}
i++
}
// Print Shopping List.
for (s in shoppingList) {
println(s)
}
// Output.
/*
Shopping(a="egg", b="dairy")
Shopping(a="chicken", b="meat")
Shopping(a="apple", b="fruit")
*/
data class Shopping(val a: String, val b: String)
Never a good idea to use regex to match parenthesis.
I would suggest a step-by-step approach:
You could first match the name and the value by
(\w+)=(.*)
There you get the name in group 1 and the value in group 2 without caring about any subsequent = characters that might appear in the value.
If you then want to split the value, I would get rid of start and end parenthesis first by matching by
(?<=\[\().*(?=\)\])
(or simply cut off the first and last two characters of the string, if it is always given it starts with [( and ends in )])
Then get the single list entries from splitting by
\),\(
(take care that the split operation also takes a regex, so you have to escape it)
And for each list entry you could split that simply by
,\s*
or, if you want the quote character to be removed, use a match with
\"(.*)\",\s*\"(.*)\"
where group 1 contains the key (left of equals sign) and group 2 the value (right of equals sign)

How to use Lucene's DistinctValuesCollector?

My objective is to collect distinct values of select fields to provided them as filter options for the frontend. DistinctValuesCollector seems to be the tool for this, however since I haven't found code sample and documentation except for the Javadocs I can't currently correctly construct this collector. Can anyone provide an example?
This is my attempt which doesn't deliver the desired distinct values of the field PROJEKTSTATUS.name.
val groupSelector = TermGroupSelector(PROJEKTSTATUS.name)
val searchGroup = SearchGroup<BytesRef>()
val valueSelector = TermGroupSelector(PROJEKTSTATUS.name)
val groups = mutableListOf(searchGroup)
val distinctValuesCollector = DistinctValuesCollector(groupSelector, groups, valueSelector)
That field is indexed as follows:
document.add(TextField(PROJEKTSTATUS.name, aggregat.projektstatus, YES))
document.add(SortedDocValuesField(PROJEKTSTATUS.name, BytesRef(aggregat.projektstatus)))
Thanks to #andrewJames's hint to a test class I could figure it out:
fun IndexSearcher.collectFilterOptions(query: Query, field: String, topNGroups: Int = 128, mapper: Function<String?, String?> = Function { it }): Set<String?> {
val firstPassGroupingCollector = FirstPassGroupingCollector(TermGroupSelector(field), Sort(), topNGroups)
search(query, firstPassGroupingCollector)
val topGroups = firstPassGroupingCollector.getTopGroups(0)
val groupSelector = firstPassGroupingCollector.groupSelector
val distinctValuesCollector = DistinctValuesCollector(groupSelector, topGroups, groupSelector)
search(query, distinctValuesCollector)
return distinctValuesCollector.groups.map { mapper.apply(it.groupValue.utf8ToString()) }.toSet()
}

Share Function Not Working But Same Code Between Apps

Ok, so I am trying to figure out what I am doing wrong here and I'm at a loss. I created one app with a share function to be able to email the data that is put in for later use. That code works fine and is below:
val shareButton1 = findViewById<Button>(R.id.shareButton)
shareButton1.setOnClickListener {
val contractNumber = findViewById<EditText>(R.id.contractNumber)
val conNumber = findViewById<TextView>(R.id.contractNum)
val desNumber = findViewById<EditText>(R.id.desNumber)
val desNum = findViewById<TextView>(R.id.desNum)
val lotNum = findViewById<EditText>(R.id.lotNumber)
val sublotNum = findViewById<EditText>(R.id.sublotNumber)
val genNum = findViewById<TextView>(R.id.genNum)
val ranTonnage = findViewById<TextView>(R.id.ranTonnage)
val sublotTonnage = findViewById<EditText>(R.id.sublotTonnage)
val sampleTonnage = findViewById<TextView>(R.id.sampleTonnage)
val conNumber1 = conNumber.text.toString()
val contractNumber1 = contractNumber.text.toString()
val desNum1 = desNum.text.toString()
val desNumber1 = desNumber.text.toString()
val lotNum1 = lotNum.text.toString()
val sublotNum1 = sublotNum.text.toString()
val genNum1 = genNum.text.toString()
val ranTonnage1 = ranTonnage.text.toString()
val sublotTonnage1 = sublotTonnage.text.toString()
val sampleTonnage1 = sampleTonnage.text.toString()
val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_TEXT, "$conNumber1 $contractNumber1 \n$desNum1 $desNumber1 \nLot #: $lotNum1 \nSublot #: $sublotNum1" +
"\nRandom Number Generated: $genNum1 \nRandom Tonnage: $ranTonnage1 \nSublot: $sublotTonnage1" +
"\nSample Tonnage: $sampleTonnage1 ")
startActivity(Intent.createChooser(shareIntent, "Share via"))
}
Now, I've created a second app to do the same thing with some different data and it isn't wanting to work. I've reviewed the code in the share function and everything seems the exact same. That code is posted below:
val shareButton1 = findViewById<Button>(R.id.share_button)
shareButton1.setOnClickListener {
val conNumber = findViewById<TextView>(R.id.contractNum)
val conNumber1 = conNumber.text.toString()
val contractNumber = findViewById<EditText>(R.id.contractNumInput)
val contractNumber1 = contractNumber.text.toString()
val desNumber = findViewById<TextView>(R.id.desNum)
val desNumber1 = desNumber.text.toString()
val desNum = findViewById<EditText>(R.id.desNumInput)
val desNum1 = desNum.text.toString()
val truckNumber = findViewById<TextView>(R.id.truckNum)
val truckNumber1 = truckNumber.text.toString()
val truckNum = findViewById<EditText>(R.id.truckNumInput)
val truckNum1 = truckNum.text.toString()
val cemDeliveredText = findViewById<TextView>(R.id.cementType1)
val cemDeliveredCalc = findViewById<TextView>(R.id.cementType1Calculated)
val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "text/plain"
shareIntent.putExtra(Intent.EXTRA_INTENT, "$conNumber1 $contractNumber1 \n$desNumber1 $desNum1 \nTruck #: $truckNum1" +
"\nCement/Type1: $cemDeliveredCalc")
startActivity(Intent.createChooser(shareIntent, "Share via"))
}
I know there has to be something simple I am missing. Like I said, the first app code works exactly as expected and pulls all the information. The second app code doesn't pull anything at all. Any help on this would be greatly appreciated as I just seem to be running in circles.
the issue with your code is in second app you can see you send
shareIntent.putExtra(Intent.EXTRA_INTENT, "$conNumber1 $contractNumber1 \n$desNumber1 $desNum1 \nTruck #: $truckNum1" +
"\nCement/Type1: $cemDeliveredCalc")
where cemDeliveredCalc is an object that's why it's not working.
you forgotted below line in your code. Add this line
val cemDeliveredCalc1 = cemDeliveredCalc.text.toString()
and then pass cemDeliveredCalc1 instead of cemDeliveredCalc
shareIntent.putExtra(Intent.EXTRA_TEXT, "$conNumber1 $contractNumber1 \n$desNumber1 $desNum1 \nTruck #: $truckNum1" +
"\nCement/Type1: $cemDeliveredCalc1")

CharBuffer to string?

How to get the string "hi" from the CharBuffer? toString() does not seem to work.
val a = CharBuffer.allocate(10);
a.put('h');
a.put('i');
val b = a.toString();
Variable states after running the code above:
CharBuffer is pretty low-level and really meant for I/O stuff, so it may seem illogical at first. In your example it actually returned a string containing remaining 8 bytes that you didn't set. To make it return your data you need to invoke flip() like this:
val a = CharBuffer.allocate(10);
a.put('h');
a.put('i');
a.flip()
val b = a.toString();
You can find more in the docs of the Buffer
For more typical use cases it is much easier to use StringBuilder:
val a = StringBuilder()
a.append('h')
a.append('i')
val b = a.toString()
Or even use a Kotlin util that wraps StringBuilder:
val b = buildString {
append('h')
append('i')
}

Kotlin: how to swap character in String

I would like to swap a string from "abcde" to "bcdea". So I wrote my code as below in Kotlin
var prevResult = "abcde"
var tmp = prevResult[0]
for (i in 0..prevResult.length - 2) {
prevResult[i] = prevResult[i+1] // Error on preveResult[i]
}
prevResult[prevResult.length-1] = tmp // Error on preveResult[prevResult.lengt-1]
It errors out as stated above comment line. What did I do wrong? How could I fix this and get what I want?
Strings in Kotlin just like in Java are immutable, so there is no string.set(index, value) (which is what string[index] = value is equivalent to).
To build a string from pieces you could use a StringBuilder, construct a CharSequence and use joinToString, operate on a plain array (char[]) or do result = result + nextCharacter (creates a new String each time -- this is the most expensive way).
Here's how you could do this with StringBuilder:
var prevResult = "abcde"
var tmp = prevResult[0]
var builder = StringBuilder()
for (i in 0..prevResult.length - 2) {
builder.append(prevResult[i+1])
}
builder.append(tmp) // Don't really need tmp, use prevResult[0] instead.
var result = builder.toString()
However, a much simpler way to achieve your goal ("bcdea" from "abcde") is to just "move" one character:
var result = prevResult.substring(1) + prevResult[0]
or using the Sequence methods:
var result = prevResult.drop(1) + prevResult.take(1)
You can use drop(1) and first() (or take(1)) to do it in one line:
val str = "abcde"
val r1 = str.drop(1) + str.first()
val r2 = str.drop(1) + str.take(1)
As to your code, Kotlin String is immutable and you cannot modify its characters. To achieve what you want, you can convert a String to CharArray, modify it and then make a new String of it:
val r1 = str.toCharArray().let {
for (i in 0..it.lastIndex - 1)
it[i] = it[i+1]
it[it.lastIndex] = str[0] // str is unchanged
String(it)
}
(let is used for conciseness to avoid creating more variables)
Also, you can write a more general version of this operation as an extension function for String:
fun String.rotate(n: Int) = drop(n % length) + take(n % length)
Usage:
val str = "abcde"
val r1 = str.rotate(1)
Simpler solution: Just use toMutableList() to create a MutableList of Char and then join it all together with joinToString.
Example:
Given a String input, we want to exchange characters at positions posA and posB:
val chars = input.toMutableList()
val temp = chars[posA]
chars[posA] = chars[posB]
chars[posB] = temp
return chars.joinToString(separator = "")
Since Strings are immutable, you will have to copy the source string into an array, make changes to the array, then create a new string from the modified array. Look into:
getChars() to copy the string chars into an array.
Perform your algorithm on that array, making changes to it as needed.
Convert the modified array back into a String with String(char[]).