Перемешать определенное количество строк в массиве строк в Java

У меня длинный текстовый файл, и мне нужно перемешать все слова, длина которых превышает 4 буквы, но другие слова должны оставаться на том же месте. Это без с использованием модуля Коллекции.

Мне удается перетасовать все строки в массиве, но я не могу понять, как перетасовать только часть.

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;

Спасибо!

Вы можете добавить первый цикл, в котором будут храниться индексы слов длиной более 4 букв.

Arnaud 23.10.2018 14:10
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
65
3

Ответы 3

Вы меняете местами только два слова, если оба длиннее 4 символов, в противном случае вы сохраняете их в исходной позиции:

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;
    }
}

Обновлено: если количество длинных слов очень мало по сравнению с количеством коротких слов, этот цикл может вести себя плохо (поскольку он не сможет поменять местами большую часть длинных слов), поэтому вы можете улучшить его следующим образом:

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;
    }
}

При генерации случайной позиции для слова, длина которого превышает 4 символа, вы проверяете, есть ли в новой позиции также слово, содержащее более 4 символов. Если нет, вы продолжаете генерировать новую случайную позицию, пока не найдете подходящую.

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;
}

Ситуация, которая может возникнуть, если у вас есть только одно слово, состоящее из более чем 4 символов, что означает, что бессмысленно даже пытаться рандомизировать их, и вы можете потратить много времени на генерацию случайных позиций безрезультатно. Чтобы оптимизировать это, вы можете сначала проверить, меньше ли у вас двух длинных слов, и если да, то вам ничего не нужно делать.

    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;

            }
        }            
    }

Вот версия, которая адаптирует Алгоритм Дюрстенфельда. Обратите внимание, что ThreadLocalRandom предпочтительнее 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;
}

OP не сказал, что нельзя использовать потоки, только коллекции. Если это проблема, можно заменить инициализацию indices простым циклом для инициализации массива int того же размера, что и textArray, используя переменную i для отслеживания количества введенных индексов (чтобы он был объявлен и инициализирован перед основным циклом for).

Другие вопросы по теме