I have txt file for example:
useless text
-- modelName
model parameters
model parameters
-- modelName
model parameters
model parameters
e.t.c
I need to split this file into List where the elements of the list is model with model parametrs.
My algoritm for this
File(FILEPATH).eachLine { line ->
if (line =regExpForModelName) {
while(line!=regExpForModelName)
model.add(line)
}
}
while(line!=regExpForModelName) is clearly wrong
You could do it with a simple state machine like so:
enum State {
SCANNING, PARSING
}
def parseFile(String filename) {
def key = null
def result = []
def mode = State.SCANNING
new File(filename).eachLine { line ->
switch(mode) {
case State.SCANNING:
if(line.startsWith('--')) {
key = (line - '--').trim()
result << [name:key, lines:[]]
mode = State.PARSING
}
break
case State.PARSING:
if(line.size() == 0) {
mode = State.SCANNING
}
else {
result[-1].lines << line
}
}
result
}
}
def results = parseFile('/tmp/file.txt')
results.each {
println it
}
So it starts off SCANNING, and then when it finds a header item, it adds a new element to the list and switches to PARSING
Then it keeps PARSING (and adding lines to the list) until it hits an empty line, when it switches back into a SCANNING state
Related
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)
}
I'm reading a text file and have the syntax set up correctly to do so. What I want to do now is append all the integers into an array, but when I try to use a print statement to check what's going on, nothing shows up in the terminal.
package lecture
import scala.io.{BufferedSource, Source}
object LectureQuestion {
def fileSum(fileName: String): Int = {
var arrayOfnumbers = Array[String]()
var fileOfnumbers: BufferedSource = Source.fromFile(fileName)
for (line <- fileOfnumbers.getLines()){
val splits: Array[String] =line.split("#")
for (number <- splits){
arrayOfnumbers :+ number
println(arrayOfnumbers.mkString(""))
}
//println(splits.mkString(" "))
}
3
}
def main(args: Array[String]): Unit = {
println(fileSum("data/fileOfnumbers.txt"))
}
}
I set up a blank array to append the numbers to. I tried switching var to val, but that wouldn't make sense as var is mutuable, meaning it can change. I'm pretty sure the way to add things to an array in Scala is :+, so I'm not sure what's going on.
In Scala all you would need is flatMap the List of a List and then sum the result.
Here your example simplified, as we have extracted the lines already:
import scala.util.Try
def listSum(lines: List[String]): Int = {
(for{
line <- lines
number <- line.split("#").map(n => Try(n.trim.toInt).getOrElse(0))
} yield number).sum
}
listSum(List("12#43#134#bad","13#54#47")) // -> 303
No vars, resp. no mutability needed. Just a nice for-comprehension;).
And for comparison the solution with flatMap:
def listSum(lines: List[String]): Int = {
lines
.flatMap(_.split("#").map(n => Try(n.trim.toInt).getOrElse(0)))
.sum
}
I am quite new to coding, so simple tasks seems like the mount Everest. I have created a Switch statement for a player to choose 3 out of 4 characters to play with. I' d like him/her to name their characters uniquely.
I tried by adding a "parameter [String]" to the method and inside it, adding each characters name, using a "for Loop" to check if a character has already be named this way.
The thing is that I keep looping and can' t sort out how to name each character uniquely.
If someone has any clue, thanks to answer.
func makeTheTeam(listOfName: [String]) {
var listOfName = listOfName
// Presents all the fighter available
gameAction.charactersPresentation()
while listOfFighters.count < 3 {
print("\nInput a number associated to select a fighter:")
if let userChoice = readLine() {
print("Name your fighter:")
if let nameChoice = readLine() {
switch userChoice {
case "1":
listOfFighters.append(Warrior(fighterName: "\(nameChoice)"))
case "2":
listOfFighters.append(Wizard(fighterName: "\(nameChoice)"))
case "3":
listOfFighters.append(Colossus(fighterName: "\(nameChoice)"))
case "4":
listOfFighters.append(Dwarf(fighterName: "\(nameChoice)"))
default:
print("You have not chosen three characters to enter the ring!! \n\nEnter a number associated to a fighter...")
}
}
}
}
}
For getting rid of the "unique" names issue, you could:
1- Get the benefit of using Sets, by converting listOfName to a set and check the counts:
if Set(listOfName).count == listOfName.count {
// unique names, we are good to go
} else {
// similar names...
}
OR
2- if your desired behavior is to check the array sequentially after adding each element, you could use contains. As an example of the basic usage for it:
var names = [String]()
var inputName = "Jack"
// will append "Jack"
if names.contains(inputName) {
// name is already exist
} else {
names.append(inputName)
}
inputName = "Smith"
// will append "Smith"
if names.contains(inputName) {
// name is already exist
} else {
names.append(inputName)
}
inputName = "Smith"
// will NOT append "Jack"
if names.contains(inputName) {
// name is already exist
} else {
names.append(inputName)
}
Tip:
If makeTheTeam function should receive an unspecific number of strings, I would suggest to declare it as variadic:
func makeTheTeam(listOfName: String...) { // ...
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
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