简体   繁体   中英

Shuffle a specific number of strings in a String Array in Java

I have a long textfile and I need to shuffle all the words which are longer than 4 letters but the other words need to remain in the same place. This without using the Collections module.

I can manage to shuffle all the strings in the array, but I cant figure out for the life of me how to shuffle only a part.

public static String[] getScramble(String text) {
    Random rgen=new Random();
    String[] textArray=text.split(" ");
    for(int i=0;i<textArray.length;i++){
        int randPos=rgen.nextInt(textArray.length);
        String temp=textArray[i];

        if (textArray[i].length()>4){
            textArray[i]=textArray[randPos];
            textArray[randPos]=temp;

        }else{
            textArray[i]=textArray[i];
        }

    }

    return textArray;

Thanks!

You only swap two words if both are larger than 4 characters, otherwise you keep them in the original position:

for(int i = 0; i < textArray.length; i++) {
    int randPos = rgen.nextInt(textArray.length);
    if (textArray[i].length() > 4 && textArray[randPos].length() > 4){
        String temp = textArray[i];
        textArray[i]=textArray[randPos];
        textArray[randPos]=temp;
    }
}

EDIT: if the number of long words is very small compared to the number of short words, this loop may behave badly (since it will fail to swap most of the long words), so you can improve it as follows:

for(int i=0;i<textArray.length;i++){
    if (textArray[i].length() > 4) {
        // find a long word to swap textArray[i] with 
        int randPos=rgen.nextInt(textArray.length);
        while (textArray[randPos].length() <= 4){
            randPos=rgen.nextInt(textArray.length);
        }
        // swap the two long words
        String temp=textArray[i];
        textArray[i]=textArray[randPos];
        textArray[randPos]=temp;
    }
}

When generating the random position for a word that is longer than 4 characters, you check to see if the new position also has a word with more than 4 characters. If not, you keep generating a new random position until you find one that works.

public static String[] getScramble(String text) {
    Random rgen = new Random();
    String[] textArray = text.split(" ");

    for (int i = 0; i < textArray.length; i++) {
        if( textArray[i].length() > 4) {
            String temp = textArray[i];

            int randPos = rgen.nextInt(textArray.length);
            while( textArray[randPos].length() <= 4 ){
                randPos = rgen.nextInt(textArray.length);
            }

            textArray[i] = textArray[randPos];
            textArray[randPos] = temp;

        }
    }

    return textArray;
}

A situation that might arise is if you have only one word with more than 4 characters, which means it's pointless to even try to randomize them, and you might waste a lot of time generating random positions to no avail. To optimize this, you can first check if you have less than 2 long words, and if so you don't need to do anything.

    int longWordCount = 0;
    for (int i = 0; i < textArray.length; i++) {
        if( textArray[i].length() > 4 )
            longWordCount++;

        if( longWordCount == 2 )
            break;
    }

    if( longWordCount > 1 ) {
        for (int i = 0; i < textArray.length; i++) {
            if (textArray[i].length() > 4) {
                String temp = textArray[i];

                int randPos = rgen.nextInt(textArray.length);
                while (textArray[randPos].length() <= 4) {
                    randPos = rgen.nextInt(textArray.length);
                }

                textArray[i] = textArray[randPos];
                textArray[randPos] = temp;

            }
        }            
    }

Here's a version that adapts Durstenfeld's algorithm . Note that ThreadLocalRandom is preferable to Random .

public static String[] getScramble(String text) {
    ThreadLocalRandom rgen = ThreadLocalRandom.current();
    String[] textArray = text.split(" ");
    int[] indices = IntStream.range(0, textArray.length)
        .filter(i -> textArray[i].length() > 4)
        .toArray();
    for (int i = indices.length; i > 1; --i) {
        int j = indices[rgen.nextInt(i)];
        int k = indices[i - 1];
        if (j != k) {
            String tmp = textArray[j];
            textArray[j] = textArray[k];
            textArray[k] = tmp;
        }
    }
    return textArray;
}

The OP didn't say that Streams couldn't be used, only Collections. If that's a problem, one can replace the initialization of indices with a simple loop to initialize an array of int of the same size as textArray , using the variable i to keep track of the number of indices entered (so it would be declared and initialized before the main for loop).

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