Jaki jest najszybszy sposób czytania z System.in w Javie?

Czytam kilka liczb całkowitych oddzielonych spacjami lub znakami nowej linii od standardu w użyciu Scanner(System.in).

Czy Jest jakiś szybszy sposób na zrobienie tego w Javie?

Author: skaffman, 2011-08-13

9 answers

Czy Jest jakiś szybszy sposób na zrobienie tego w Javie?

Tak. Skaner jest dość powolny (przynajmniej według mojego doświadczenia).

Jeśli nie musisz sprawdzać poprawności danych wejściowych, proponuję po prostu zawinąć strumień w BufferedInputStream i użyć czegoś takiego String.split / Integer.parseInt.


Małe porównanie:

Odczyt 17 megabajtów (4233600 numerów) przy użyciu tego kodu

Scanner scanner = new Scanner(System.in);
while (scanner.hasNext())
    sum += scanner.nextInt();

Took on my machine 3.3 sekund . while this snippet

BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = bi.readLine()) != null)
    for (String numStr: line.split("\\s"))
        sum += Integer.parseInt(numStr);

Zajęło 0,7 sekundy .

Przez dalsze zamieszanie w kodzie (iteracja nad line z String.indexOf / String.substring) można go dostać się do około 0.1 sekundy dość łatwo, ale myślę, że odpowiedziałem na twoje pytanie i nie chcę, aby przekształcić to w jakiś kod golf.

 95
Author: aioobe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-13 07:05:32

Stworzyłem małą klasęInputReader , która działa tak samo jak Scanner Javy, ale przewyższa ją szybkością o wiele wielkości, w rzeczywistości przewyższa również BufferedReader. Oto wykres słupkowy, który pokazuje wydajność stworzonej przeze mnie klasy InputReader odczytującej różne typy danych ze standardowego wejścia:

Tutaj wpisz opis obrazka

Oto dwa różne sposoby znajdowania sumy wszystkich liczb pochodzących z System.in użycie klasy InputReader:

int sum = 0;
InputReader in = new InputReader(System.in);

// Approach #1
try {

    // Read all strings and then parse them to integers (this is much slower than the next method).
    String strNum = null;
    while( (strNum = in.nextString()) != null )
        sum += Integer.parseInt(strNum);

} catch (IOException e) { }

// Approach #2
try {

    // Read all the integers in the stream and stop once an IOException is thrown
    while( true ) sum += in.nextInt();

} catch (IOException e) { }
 3
Author: will.fiset,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-06 18:07:00

Jeśli pytasz z konkurencyjnego punktu widzenia programowania, gdzie jeśli zgłoszenie nie jest wystarczająco szybkie, to będzie TLE.
Następnie możesz sprawdzić następującą metodę, aby pobrać ciąg z System.in. Wziąłem z jednego z najlepszych programistów w Javie (konkurencyjne strony)

private String ns()
{
    int b = skip();
    StringBuilder sb = new StringBuilder();
    while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
        sb.appendCodePoint(b);
        b = readByte();
    }
    return sb.toString();
}`
 3
Author: Loki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-07 07:36:30

Możesz czytać z System.in cyfra po cyfrze. Spójrz na tę odpowiedź: https://stackoverflow.com/a/2698772/3307066 .

Kopiuję tu kod (ledwo zmodyfikowany). Zasadniczo czyta liczby całkowite, oddzielone od siebie wszystkim, co nie jest cyfrą. (Podziękowania dla oryginalnego autora.)

private static int readInt() throws IOException {
    int ret = 0;
    boolean dig = false;
    for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c >= '0' && c <= '9') {
            dig = true;
            ret = ret * 10 + c - '0';
        } else if (dig) break;
    }
    return ret;
}
W moim problemie kod ten wynosił ok. 2 razy szybciej niż przy użyciu StringTokenizer, który był już szybszy niż String.split(" "). (Problem polegał na odczytaniu 1 miliona liczb całkowitych z maksymalnie 1 miliona każda.)
 1
Author: jbarrameda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:30

StringTokenizer jest o wiele szybszym sposobem odczytu wejść łańcuchowych oddzielonych tokenami.

Sprawdź poniższy przykład, aby odczytać ciąg liczb całkowitych oddzielony spacją i zapisać w arraylist,

String str = input.readLine(); //read string of integers using BufferedReader e.g. "1 2 3 4"
List<Integer> list = new ArrayList<>();
StringTokenizer st = new StringTokenizer(str, " ");
while (st.hasMoreTokens()) {
    list.add(Integer.parseInt(st.nextToken()));
} 
 1
Author: Hetal Rachh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-26 08:38:08

Z perspektywy programowania ta dostosowana Klasa Scan i Print jest o wiele lepsza niż wbudowane w Javę klasy Scanner i BufferedReader.

import java.io.InputStream;
import java.util.InputMismatchException;
import java.io.IOException;

public class Scan
{

private byte[] buf = new byte[1024];

private int total;
private int index;
private InputStream in;

public Scan()
{
    in = System.in;
}

public int scan() throws IOException
{

    if(total < 0)
        throw new InputMismatchException();

    if(index >= total)
    {
        index = 0;
        total = in.read(buf);
        if(total <= 0)
            return -1;
    }

    return buf[index++];
}


public int scanInt() throws IOException
{

    int integer = 0;

    int n = scan();

    while(isWhiteSpace(n))   /*  remove starting white spaces   */
        n = scan();

    int neg = 1;
    if(n == '-')
    {
        neg = -1;
        n = scan();
    }

    while(!isWhiteSpace(n))
    {

        if(n >= '0' && n <= '9')
        {
            integer *= 10;
            integer += n-'0';
            n = scan();
        }
        else
            throw new InputMismatchException();
    }

    return neg*integer;
}


public String scanString()throws IOException
{
    StringBuilder sb = new StringBuilder();

    int n = scan();

    while(isWhiteSpace(n))
        n = scan();

    while(!isWhiteSpace(n))
    {
        sb.append((char)n);
        n = scan();
    }

    return sb.toString();
}


public double scanDouble()throws IOException
{
    double doub=0;
    int n=scan();
    while(isWhiteSpace(n))
    n=scan();
    int neg=1;
    if(n=='-')
    {
        neg=-1;
        n=scan();
    }
    while(!isWhiteSpace(n)&& n != '.')
    {
        if(n>='0'&&n<='9')
        {
            doub*=10;
            doub+=n-'0';
            n=scan();
        }
        else throw new InputMismatchException();
    }
    if(n=='.')
    {
        n=scan();
        double temp=1;
        while(!isWhiteSpace(n))
        {
            if(n>='0'&&n<='9')
            {
                temp/=10;
                doub+=(n-'0')*temp;
                n=scan();
            }
            else throw new InputMismatchException();
        }
    }
    return doub*neg;
}

public boolean isWhiteSpace(int n)
{
    if(n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1)
        return true;

    return false;
}

public void close()throws IOException
{
    in.close();
}
}

I dostosowana Klasa wydruku może być następująca

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Print
{
private BufferedWriter bw;

public Print()
{
    this.bw = new BufferedWriter(new OutputStreamWriter(System.out));
}


public void print(Object object)throws IOException
{
    bw.append("" + object);
}

public void println(Object object)throws IOException
{
    print(object);
    bw.append("\n");
}


public void close()throws IOException
{
    bw.close();
}

}
 0
Author: Paul92,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-21 15:33:29

Możesz użyć BufferedReader do odczytu danych

BufferedReader inp = new BufferedReader(new InputStreamReader(System.in));
  int t = Integer.parseInt(inp.readLine());
  while(t-->0){
    int n = Integer.parseInt(inp.readLine());
    int[] arr = new int[n];
    String line = inp.readLine();
    String[] str = line.trim().split("\\s+");
    for(int i=0;i<n;i++){
      arr[i] = Integer.parseInt(str[i]);
    }

I do drukowania StringBuffer

    StringBuffer sb = new StringBuffer();
    for(int i=0;i<n;i++){
              sb.append(arr[i]+" "); 
            }
    System.out.println(sb);
 0
Author: Shywalker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-14 13:26:31

Oto pełna wersja szybkiego czytelnika i pisarza. Użyłem też buforowania.

import java.io.*;
import java.util.*;


public class FastReader {
    private static StringTokenizer st;
    private static BufferedReader in;
    private static PrintWriter pw;


    public static void main(String[] args) throws IOException {

        in = new BufferedReader(new InputStreamReader(System.in));
        pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        st = new StringTokenizer("");

        pw.close();
    }

    private static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }
    private static long nextLong() throws IOException {
        return Long.parseLong(next());
    }
    private static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
    private static String next() throws IOException {
        while(!st.hasMoreElements() || st == null){
            st = new StringTokenizer(in.readLine());
        }
        return st.nextToken();
    }
}
 0
Author: mr.sanatbek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-02 13:25:08

Odczyt z dysku, raz po raz, powoduje spowolnienie skanera. Lubię używać kombinacji BufferedReader i Scanner, aby uzyskać najlepsze z obu światów. tj. szybkość BufferredReader oraz bogate i łatwe API skanera.

Scanner scanner = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
 0
Author: Heisenberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-26 03:56:02