Always getting the last item in a list using split - arrays

As of right now i retrieve the first item in my list that i generate by using split, but i also want the last item in a seperate function.
The problem ist the list is generated from an ocr and is never the same length or size.
is there a way in kotlin to always get the last item?
This is the code for getting the first :
fun String.firstLine(): String {
if (this.isEmpty()) return ""
return this.split("\n").get(0)
}

You can do something like this:
fun String.firstAndLast() = split("\n").let { it.first() to it.last() }
fun main() {
val s = "first line\nsecond line\nlast line"
val (first, last) = s.firstAndLast()
println(first)
println(last)
}
output is:
first line
last line
The fun will split, then use the resulting list and get only the first and last element, returning a Pair<String, String>, which can be easily deconstructed with val (first, last), then those values can be used separately.
Edit: for the penultimate as well, I don't think that a list might be a good idea. I personally would go with an object of sorts, or with a Triple.
Class way:
class NoNameIdeas(
val first: String = "",
val penultimate: String = "",
val last: String = ""
) {
companion object {
fun fromString(string: String): NoNameIdeas {
val l = string.split("\n")
val first = l.first()
return when (l.size) {
1 -> NoNameIdeas(first = first)
2 -> NoNameIdeas(first = first, penultimate = "what should this be?", last = l.last())
else -> NoNameIdeas(first = first, penultimate = l[l.lastIndex - 1], last = l.last())
}
}
}
}
fun main() {
val string = "first line\nsecond line\nsecond last\nlast line"
val result = NoNameIdeas.fromString(string)
println(result.first)
println(result.penultimate)
println(result.last)
}
As you can guess, I have no idea how to name this object. Another issues is, what should we do with the penultimate, if we only have 2 lines in total? It can be the same as the first, or it can be empty, or it can be the same as the last. That is your decision, it also might never happen, only you know what data you have.
Another way of doing it without a class, but by using a triple:
Triple way:
fun main() {
val string = "first line\nsecond line\nsecond last\nlast line"
val result = string.firstPenultimateAndLast()
println(result.first)
println(result.second)
println(result.third)
}
fun String.firstPenultimateAndLast(): Triple<String, String, String> {
val l = split("\n")
val first = l.first()
var penultimate = "" //same as the class, what happens when we only have 2 lines?
var last = l.first() //if we only have 1, then I guess that the first is the last as well, will get a new value otherwise
when (l.size) {
2 -> last = l.last()
else -> {
penultimate = l[lastIndex - 1]
last = l.last()
}
}
return Triple(first, penultimate, last)
}

Related

Tokens not in order for tokenization / lexer (kotlin)

I am creating a tokenization system in Kotlin / JVM that takes in a file and returns each char or sequence of chars as a token. For some reason, whenever I tokenized a string, it finds the second instance of s "string" token before moving onto the next token, or in other words, the tokens are not in order. I think it might have to do with the loop, but I just can't figure it out. I am still learning Kotlin, so if anyone could give me pointers as well, that'd be great! Much appreciated any help.
output of tokens :
[["chello", string], ["tomo", string], [:, keyV], ["hunna", string], ["moobes", string], ["hunna", string]]
My file looks like this.
STORE "chello" : "tomo" as 1235312
SEND "hunna" in Hollo
GET "moobes"
GET "hunna"
fun tokenCreator (file: BufferedReader) {
var lexicon : String = file.readText()
val numRegex = Regex("^[1-9]\\d*(\\.\\d+)?\$")
val dataRegex = Regex("[(){}]")
val token = mutableListOf<List<Any>>()
for((index, char) in lexicon.withIndex()) {
println(char)
when {
char.isWhitespace() -> continue
char.toString() == ":" -> token.add(listOf(char.toString(), "keyV") )
char.toString().matches(Regex("[()]")) -> token.add(listOf(char, "group") )
char.toString().matches(dataRegex) -> token.add(listOf(char, "data_group" ) )
char == '>' -> token.add(listOf(char.toString(), "verbline") )
char == '"' -> {
var stringOf = ""
val firstQuote = lexicon.indexOf(char)
val secondQuote = lexicon.indexOf(char, firstQuote + 1)
if(firstQuote == -1 || secondQuote == -1) {
break
}
for(i in firstQuote..secondQuote) {
stringOf += lexicon[i]
}
lexicon = lexicon.substring(secondQuote + 1, lexicon.length)
token.add(listOf(stringOf, "string"))
}
}
}
println(token)
}
Changing the content while iterating seems like a recipe for confusion...
And you don't seem to increment the index to skip over consumed content. I'd recommend to change the loop in a way that allows you to skip over content you have consumed
I'd also remove this line:
lexicon = lexicon.substring(secondQuote + 1, lexicon.length)
Then replace
val firstQuote = lexicon.indexOf(char)
with
val firstQuote = index
You can also use substring instead of iteration for stringOf
val stringOf = lexicon.substring(
Moreover, using toString to check for ':' seems inefficient

Closest-match string-array sorting in Swift

Using Swift4, I would like to sort a string-array according to the closest match to a given searchTerm. Important is to me that if the searchTerm can be found as an exact-match, then the returnArray should show this searchTerm upfront !
Example: Given the Array = ["Hello world", "Hello Jamaica", "Hello", "Family", "Hel"]
And the searchTerm = "Hello", the algorithm should return:
["Hello", "Hello world", "Hello Jamaica", "Hel", "Family"].
Approach 1:
I tried to use FuzzyMatching - and it somehow worked (i.e. it did sort the inputArray according to a given searchTerm, however it did not put the exact-matches upfront ! i.e. With FuzzyMatching I achieved a good sorting according to substring-matches and syntactic sorting. But it did not bring me the exact-matches upfront in the returnArray).
Approach 2:
Then I tried my own algorithm - (see code below). But if there are several strings in the array that all start with my searchTerm (i.e. have searchTerm as a prefix), then somehow my algo does not a good job.
static func bestMatchFilterdStringArray(inputArray: [String], searchTerm: String) -> [String] {
let matchingTerms = inputArray
.filter { $0.range(of: searchTerm, options: .caseInsensitive) != nil }
.sorted { ($0.hasPrefix(searchTerm) ? 0 : 1) < ($1.hasPrefix(searchTerm) ? 0 : 1) }
return matchingTerms
}
How is a "Closest-match string-array sorting" done in Swift4? Especially bringing me exact-matches upfront in the returnArray? Any help appreciated!
You can use Levenshtein distance score to compare your search term with every string in the array, and the one with the highest score will be the first term in your result array etc. Your result will be an array of strings sorted in descending order of the score.
Following extension to string can be used to get Levenshtein distance score. In this algorithm, higher the value, better the equality.
extension String {
func levenshteinDistanceScore(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Double {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating:0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
// maximum string length between the two
let lowestScore = max(firstString.count, secondString.count)
if let validDistance = last.last {
return 1 - (Double(validDistance) / Double(lowestScore))
}
return 0.0
}
}

How to implement readLine()!!.toIntArray() on Kotlin?

I would like to implement a function or some way to store an array sequentially from a console. Something like this: readLine()!!.toIntArray()
Would it be convenient to use a loop for this or could it be avoided?
And then you can access them using the index of the array.
fun main(args: Array<String>) {
myFunction()
}
A:
fun myFunction() {
println(" . First number: ")
val num1:Float = readLine()!!.toFloat()
println(" . Second number: ")
val num2:Float = readLine()!!.toFloat()
println(" . Third number: ")
val num3:Float = readLine()!!.toFloat()
println(" . Fourth number: ")
val num4:Float = readLine()!!.toFloat()
val result:Float = (num1+num2) + (num3*num4)
print("The result is: $result")
}
B:
fun myFunction() {
println("Enter four numbers ...")
// val numbers:IntArray = intArrayOf(45, 22, 10, 13)
val numbers:IntArray = readLine()!!.toIntArray() //HERE: toIntArray() isn't defined
val result:Int = (numbers[0]+numbers[1]) + (numbers[2]*numbers[3])
print("The result is: $result")
}
When defining the Array I will have to indicate the amount of values that I want to be read from the console, that is, the size of the Array.
Or is there another way to stop reading data in the console?
In short, I want to move from block A to the idea of block B.
SOLUTION
println("Enter four numbers ...")
val numbers = readLine()!!.split(" ").map { it.toInt() }
val result:Int = (numbers[0]+numbers[1]) + (numbers[2]*numbers[3])
print("The result is: $result")
You don't need a loop. It can be done with map:
val numbers = readLine()!!.split(" ").map { it.toInt() }
If you need to read the numbers from separate lines like in your examples:
val list = List(4) { readline()!!.toFloat() }
The same can be done with arrays, but it is recommended to use lists in Kotlin

identify last element of an array in Groovy 'for' statement

Is it possible to identify the last element of an array within a 'for' statement like the following?
for (ai in list) {
}
It's not a requirement, it's mainly curiosity.
You can with enough trickery (i.e. metaprogramming). The classes below define a custom iterator that dynamically injects a readonly last property into each element and a custom List implementation for returning the custom iterator.
import groovy.transform.TupleConstructor
#TupleConstructor
class LastAwareIterator<T> implements Iterator<T> {
Iterator itr
boolean hasNext() {
itr.hasNext()
}
void remove() {
itr.remove()
}
T next() {
T obj = itr.next()
boolean last = !itr.hasNext()
obj.metaClass.isLast << { -> last }
obj
}
}
class LastAwareList<T> extends ArrayList<T> {
Iterator<T> iterator() {
new LastAwareIterator(super.iterator())
}
}
When you coerce your list into LastAwareList using as, you can use the last property within the for loop body.
def list = [1,2,3,4,2] as LastAwareList
for (ai in list) {
if (ai.last) {
print 'and '
}
print "$ai "
}
// prints 1 2 3 4 and 2
I had originally wanted to use ExpandoMetaClass to directly override the iterator method, avoiding the need for as LastAwareList, but couldn't get it working. If I ever figure it out, I'll update the post.
A counter has to be maintained to check the last item in the list.
def printList(list) {
int x = 1
for ( ai in list ) {
if ( x == list.size() ) println "and"
println ai
x++
}
println ""
}
printList([1,2,3,4,5])
printList([1,2,3,4,2])
printList([2,2,2])
printList([])
printList(null)
Also try with list having duplicate elements and the last item being a duplicate.
I know it isn't what you asked, but I just want to bring to your attention that in groovy there is a really cool way of getting the last element.
def list = [1,2,3]
println list.last()
Try this
def list = [1,2,3,4,5,6] //your list
def last = list.last() //got last item of list
list.each { item ->
if (item == last) { //checking last item
println ("and "+ item)
} else {
println(item)
}
}
//result : 1 2 3 4 5 and 6

Search list and return the whole entry

I try to read a textfile and find a given parameter, if this is true, it should deliver me the whole list entry.
Thats the input in the file: 100 0100045391 0400053454 0502028765251 ABH ZL1 1560112 07.06.2010 100 0100045394 0400055024 0502028766382 ABH ZL1 1601944 21.06.2010
But at the moment I just can check if this parameter is in the list or not or the given parameter himself.
import groovy.util.CharsetToolkit;
//Pathname
def pathname = "C:/mySupport-eclipse/trackandtrace.txt"
//Error State
int errorCode = 0
def bsknr = "0100045553"
//Define new file
def file = new File(pathname)
if(!file.exists())
{
errorCode = 1
}
else
{
//Read lines, seperated by tab
file.splitEachLine ('\t') {
list -> list
println list.findAll {it.contains(bsknr)}
}
}
You could use a regular expression, which would return the whole line that contains the parameter. Together with Groovy's built-in File.filterLine(Closure) method, you get something like that:
def lines = file.filterLine { line -> line ==~ /.*\t${bsknr}\t.*/ }
If you want lines to be a string, you can do:
def linesAsString = lines.toString()
If you want them to be a list, you would do:
def linesAsList = lines.toString().tokenize("\n")
Assuming you mean your input file is:
100 0100045391 0400053454 0502028765251 ABH ZL1 156011207.06.2010
100 0100045394 0400055024 0502028766382 ABH ZL1 160194421.06.2010
And assuming you mean "How can I get a list of the lines containing this string" (I have no idea what 'But at the moment I just can check if this parameter is in the list or not or the given parameter himself.' means), then you can do this:
//Pathname
def pathname = "C:/mySupport-eclipse/trackandtrace.txt"
//Error State
int errorCode = 0
def bsknr = "0100045553"
def lines = []
//Define new file
def file = new File( pathname )
if(!file.exists()) {
errorCode = 1
}
else {
//Read lines, seperated by tab
file.eachLine { line ->
if( line.split( /\t/ ).grep { bsknr } ) lines << line
}
}
println lines

Resources