简体   繁体   中英

How to iterate through large string with substrings incrementing by 1 position?

I have a String with an enormous number in it (thousands of chars):

String pi = "3.14159265358979323846264338327950288419716939937..."

I want to cycle through this string, grabbing 6 chars at a time, and checking if they match a given String:

String substring = "3.1415"

However, on each subsequent substring, I want to shift 1 position to the right of the chars in the original String:

substring = ".14159"
substring = "141592"
substring = "415926"
substring = "159265"

etc. etc.

What is the best way to do this? I have considered StringBuilder's methods, but converting to a String each iteration might be costly. String's method

substring(int beginIndex, int endIndex)

seems to approach what I'm trying to do, but I don't know if those indices can be incremented algorithmically.

I don't know if those indices can be incremented algorithmically.

These are parameters. They are values provided by you for each invocation of the method.

You are free to specify anything you want based on variables, constants, expressions, user input, or anything else. In this case, you can keep one or two variables, increment them, and pass them as parameters.

Here's an example using two variables that are both incremented by 1 each iteration:

class Main {
  public static void main(String[] args) {
    String pi = "3.14159265358979323846264338327950288419716939937...";
    for(int start=0, end=6; end <= pi.length(); start++, end++) {
      String substring = pi.substring(start, end);
      System.out.println(substring);
    }
  }
}

Here's an algorithm that's efficient at matching values. Might be more efficient then using substring methods since it short circuits as soon as values don't match the provided sequence.

public static int containsSubstring(String wholeString, String findValue) {
    //Break values into arrays
    char[] wholeArray = wholeString.toCharArray();
    char[] findArray = findValue.toCharArray();

    //Use named outer loop for easy continuation to next character place
    outerLoop:
    for(int i = 0; i < wholeArray.length; i++) {
        //Remaining values aren't large enough to contain find values so stop looking
        if(i + findArray.length > wholeArray.length) {
            break;
        }

        //Loop through next couple digits to check for matching sequence
        for(int j = 0; j < findArray.length; j++) {
            //Breaks loop as soon as a values don't match
            if(wholeArray[i + j] != findArray[j]) {
                continue outerLoop;
            }
        }

        return i; //Or 'true' of you just care whether it's in there, and set the method return to boolean
    }

    return -1; //Or 'false'
}

Or java 8 style

String pi = "3.14159265358979323846264338327950288419716939937...";
IntStream.range(0, pi.length() - 5)
        .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
        .forEach(System.out::println)
;

You have the possibility to make it parallel

String pi = "3.14159265358979323846264338327950288419716939937...";
IntStream.range(0, pi.length() - 5)
        .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
        .parallel()
        .forEach(System.out::println)
;    

Speaking about performances the classic for loop method is still a little bit faster of it; you should do some tests:

public class Main {

    static long firstTestTime;
    static long withStreamTime;

    static String pi = "3.141592653589793238462643383279502884197169399375105820974944592307816";

    public static void main(String[] args) {
        firstTest(pi);
        withStreams(pi);

        System.out.println("First Test: " + firstTestTime);
        System.out.println("With Streams: " + withStreamTime);
    }

    static void withStreams(String pi) {
        System.out.println("Starting stream test");
        long startTime = System.currentTimeMillis();

        IntStream.range(0, pi.length() - 5)
                .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
                //.parallel()
                .forEach(System.out::println)
        ;

        withStreamTime = System.currentTimeMillis() - startTime;
    }

    // By @that other guy
    static void firstTest(String pi) {
        System.out.println("Starting first test");
        long startTime = System.currentTimeMillis();

        for(int start=0, end=6; end <= pi.length(); start++, end++) {
            String substring = pi.substring(start, end);
            System.out.println(substring);
        }

        firstTestTime = System.currentTimeMillis() - startTime;
    }

}

Try to increase the greek pi length!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM