User1291
User1291

Reputation: 8182

Can I "start over" a java Scanner?

Is there a way to make a scanner start from the beginning of its input, again?

Context: I just learned that https://adventofcode.com/ is a thing.

The first task is simple enough (as first tasks often are).

You're given a series of sign-prefixed (+ or -) integer values

I.e.

-7
+16
+5
[...]

and need to add them.

No big deal.

task01.kts

import java.util.*

val scanner = Scanner(System.`in`)

private var total = 0
while(scanner.hasNext()){
    val number = scanner.nextInt()
    total += number
}

println(total)

The second task states that the read input is repeated over and over again and that we're interested in the first total to be reached twice.

Again, fairly simple:

task02.kts

import java.util.*
import java.io.File
import Task02.Result.*

sealed class Result{
    object None: Result()
    data class Found(val duplicate:Int):Result()
}

if(args.size < 1) throw IllegalStateException("please provide input file as first arg")

val input = File(args[0])

private var total = 0
private val seen = mutableSetOf(0)

private var result: Result = None
while(result is None){
    val scanner = Scanner(input)
    while(scanner.hasNext()){
        val number = scanner.nextInt()
        total += number

        if(seen.contains(total)){
            result = Found(total)
            break;
        }
        else seen.add(total)
    }
}

println((result as Found).duplicate)

But one interesting difference between the two tasks is that while I don't care where the numbers come from in the first part, I need a File for the second.

And it got me thinking. Is there a "wrap-around scanner" or something?

Can I manually reset the Scanner's pointer?

Or can I chain Scanners such that everything the first scanner sees (including the stuff it skips over) gets passed on to the second?

You know, that kind of thing?

       Scanner1                    Scanner2
[ O | L | L | E | H ]        [   |   |   |   |   ]
[   | O | L | L | E ]        [   |   |   |   | H ]
[   |   | O | L | L ]        [   |   |   | E | H ]
[   |   |   | O | L ]        [   |   | L | E | H ]
[   |   |   |   | O ]        [   | L | L | E | H ]
[   |   |   |   |   ]        [ O | L | L | E | H ]

or anything else along these lines?

I have a hunch there isn't because most everything I could think of would require the caching of all input (which, depending on the input size, may not be reasonable), but I'm still curious if I haven't overlooked something.

Upvotes: 3

Views: 1614

Answers (2)

Pavel
Pavel

Reputation: 5876

If scanner can be resetted, there will be two possibilities:

1) Each time you reset, it starts reading from the file again. It does not give any benefits over creating a new one each time.

2) It saves all read data in RAM. But you can save it by yourself as well. Often it will be more efficient. In the case you can store integer instead of string which saves memory.

If you want just don't close&reopen the file each time, you can use some lower-level file-specific API like RandomAccessFile which can be reset using seek(0).

The reason that Scanner does not have seek method is that it accepts not only file but any InputStream like System.in which can't be read again by design.

Upvotes: 3

Andre Artus
Andre Artus

Reputation: 1890

If you just plan on reading the same input repeatedly then open it as a RandomAccessFile and seek back to the start on each iteration.

Of course your algorithm is assuming a constrained input. What do you do if the input consists of one line containing "+1"?

Upvotes: 1

Related Questions