Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make StdIn.isEmpty() return true?

I am using the StdIn.isEmpty() method from the Princeton libraries provided in the Algorithms Coursera algorithms course but am confused as to how it works. I have the statement

while (!StdIn.isEmpty())

with some code enclosed that reads user input but I can't seem to break out of the loop. By my understanding if I hit enter without typing in any text that should mean that standard input is empty and the while loop should be broken. I looked up the code for isEmpty but it did not clarify anything:

public static boolean isEmpty() {
    return !scanner.hasNext();
}

Can someone clarify how standard input works and help me fix my misunderstanding of this method?

like image 393
RB34 Avatar asked Apr 13 '17 20:04

RB34


2 Answers

I think that on Mac you can use CMD+D (⌘+D) to mark the end of input to the shell. See: https://www.jetbrains.com/help/idea/debug-tool-window-console.html

Keyboard Shortcuts

The ⌘D key combination allows you to send EOF (end of file), i.e. to signal that no more data can be read from a data source.

On the issue of the Princeton libraries provided in the Algorithms - Part 1 in Coursera's course, you can play a bit with their code, particularly in the class import edu.princeton.cs.algs4.StdIn;. Their implementation that uses that code is probably not the most sophisticated to play with the concepts:

while (!StdIn.isEmpty()) {
     int p = StdIn.readInt();
     int q = StdIn.readInt();

     if (!uf.connected(p, q)) {
         uf.union(p, q);
         StdOut.println(p + " " + q);
     }
}

Here's what I did:

  1. Created new Java project in IntelliJ
  2. Create new java package (will be under src)
  3. Create new class for their examples, that will have a main method
  4. Created libs folder in project
  5. Downloaded their code from http://algs4.cs.princeton.edu/code/algs4.jar and placed that jar in the libs folder
  6. Added that lib to project - on project tab in IntelliJ, right click the project > Open Module Settings > Click dependencies tab > Click '+' > JAR or directories... > choose the jar from libs folder above
  7. I changed the code in the while loop above to have a better user interaction on the shell (be creative here - instead of using the isEmpty() use a check for p and q to be both 0 to mark end of input, for example.

Now to run that just do right-click on the code that has the class with the main static method, and choose Run (CTRL+SHIFT+R).

This will avoid the dreaded CMD+D and some issues that go with it if you want to write more code after the while loop - for instance, I added code to check if 2 objects are connect:

StdOut.println("Check if 2 objects are connected: ");
try {
    Scanner reader = new Scanner(System.in);  // Reading from System.in
    System.out.println("Enter first object: ");
    int n = reader.nextInt(); // Scans the next token of the input as an int.
    System.out.println("Enter second object: ");
    int m = reader.nextInt(); // Scans the next token of the input as an int.
    StdOut.println(uf.connected(n, m) ? "Connected" : "Not Connected");
} catch(Exception e) {
    // whatever...
}

Here's my very quick and dirty approach to the problem:

package com.algorithms;

import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.UF;

import java.util.Scanner;

public class Week1 {
    private static UF uf;

    public static void main(String[] args)
    {
        StdOut.println("Enter the total number of objects: ");
        int N = StdIn.readInt();

        StdOut.println("Enter the unions between any of those objects...");

        Week1.uf = new UF(N);
        while (true) {

            int p = StdIn.readInt();
            int q = StdIn.readInt();

            if (!uf.connected(p, q)) {
                Week1.uf.union(p, q);
                StdOut.println(p + " " + q);
            }

            if(p==0 && q==0) break;
        }
        checkIfConnected();
    }

    private static void checkIfConnected()
    {
        StdOut.println("Check if 2 objects are connected: ");
        try {
            Scanner reader = new Scanner(System.in);  // Reading from System.in
            System.out.println("Enter first object: ");
            int n = reader.nextInt(); // Scans the next token of the input as an int.
            System.out.println("Enter second object: ");
            int m = reader.nextInt(); // Scans the next token of the input as an int.
            StdOut.println(Week1.uf.connected(n, m) ? "Connected" : "Not Connected");
        } catch(Exception e) {}
    }
}
like image 120
Rui Carvalho Avatar answered Sep 28 '22 23:09

Rui Carvalho


Before reading each number, the program uses the method StdIn.isEmpty() to check whether there are any more numbers in the input stream. How do we signal that we have no more data to type? By convention, we type a special sequence of characters known as the end-of-file sequence. Unfortunately, the terminal applications that we typically encounter on modern operating systems use different conventions for this critically important sequence. In this book, we use Ctrl-D... Computer Science Sedgewick

Therefore isEmpty is actually isCtrl-D.

Also, try StdIn.isEmpty() in the terminal application without anything beforehand will leave you with no boolean but a standard input stream requesting inputs. So when a program like the following one runs:

public class Average
  {
     public static void main(String[] args)
     {  // Average the numbers on standard input.
        double sum = 0.0;
        int n = 0;
        while (!StdIn.isEmpty())
        {  // Read a number from standard input and add to sum.
           double value = StdIn.readDouble();
           sum += value;
           n++;
        }
        double average = sum / n;
        StdOut.println("Average is " + average);
     }
 } 

, the standard input stream pops out when decide the conditional while (!StdIn.isEmpty) for the first time instead of StdIn.readDouble(). If you then type in some numbers, return them, causing standard input stream to be non-empty, the program would then jump inside the while body. I found out this is the case by testing

> java Average
 [DrJava Input Box] (And I hit Ctrl+D here)
Average is NaN

NaN means n = 0 which means the while body was left no touched.

like image 45
eGregius Avatar answered Sep 28 '22 22:09

eGregius