Přidat otázku mezi oblíbené Zasílat nové odpovědi e-mailem Java - Alternativa za vnořené cykly?

Dobrý den,

Potřeboval bych poradit, jak nahradit vnořené cykly. Řekněme, že budu mít příklad níže.

 var array = new char[]{'a', 'b', 'c', 'd'};
var list = getVariation(array, 4);

public static ArrayList<String> getVariation(char characters[], int number_of_characters) {
        
    var length = characters.length;
    var list = new ArrayList<String>();

    switch (number_of_characters) {
        case 2 -> {
            for (var i = 0; i < length; i += 1) {
                for (var j = 0; j < length; j += 1) {
                    list.add(characters[i] + "" + characters[j]);
                }
            }
        }
        case 3 -> {
            for (var i = 0; i < length; i += 1) {
                for (var j = 0; j < length; j += 1) {
                    for (var k = 0; k < length; k += 1) {
                        list.add(characters[i] + "" + characters[j] + "" + characters[k]);
                    }
               }
           }
        }
        case 4 -> {
            for (var i = 0; i < length; i += 1) {
                for (var j = 0; j < length; j += 1) {
                    for (var k = 0; k < length; k += 1) {
                        for (var l = 0; l < length; l += 1) {
                            list.add(characters[i] + "" + characters[j] + "" + characters[k] + "" + characters[l]);
                        }
                    }
                }
            }
        }
    return list;
} 

Tento kód je už z principu nepřehledný, protože musí pro každé číslo to napsat zvlášť, jsou omezená pouze na 2,3,4 a z hlediska optimalizace je to taky děs.

Dají se, prosím Vás, nějak vnořené cykly nahradit něčím jiným? Už jenom proto, abych tam mohl zadat libovolné číslo a ne pouze 2,3,4.

Děkuji

Jsou zobrazeny jen nové odpovědi. Zobrazit všechny
Předmět Autor Datum
MichalDM
dsa
MichalDM
Jan Fiala
MichalDM
MaSo
MaSo

Chtěl bych opětovně otevřít toto téma, na které jsem zanevřel a teď jsem se k tomu opětovně vrátil. Jak už bylo zmíněno, náhrada za vnořené cykly je rekurze, kromě kódu v odpovědi, jsem našel různé způsoby, např. tento

 // add the next character to the string, or the string to the list
public void variations(List<String> list, int remaining, String soFar, int... codePoints) {
    if (remaining == 0) {
        list.add(soFar);
    } else {
        for (int i = 0; i < codePoints.length; ++i) {
            variations(list, remaining - 1,
                soFar + Character.toString(codePoints[i]), codePoints);
        }
    }
}

// recursively generate all possible combinations
public List<String> getVariation(int number, int... codePoints) {
    List<String> list = new ArrayList<>();
    variations(list, number, "", codePoints);
    return list;
} 

Tento kód jednoduše zavolám příkazem

Zmíněnou chybu java.lang.reflect.InvocationTargetException bych odsunul stranou. Tu zavinila knihovna OpenJavaFX, se kterou je více potíží než užitku (od té doby, co není součástí Java) a po odebrání chyba zmizela.

Avšak, stále tu zůstává problém s nedostatkem paměti. Pokud zavolám kód výše např. tímto příkazem

 var list = getVariation(7, "abcdefghijklmnop".codePoints().toArray()); 

Program poběží cca 3 minuty a pak zhavaruje s chybou Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Problém přetrvává i potom, co jsem NetBeans navýšil paměť na 5 GB (před tím to zhavarovalo mnohem dříve)

Nevíte, prosím Vás, jak to vyřešit? Samozřejmě je tu ještě problém s nedostatkem kapacity pole, ale to jsem chtěl jednoduše vyřešit použitím více polí.

Nicméně, to bych první musel vyřešit problém s pamětí. Popravdě se mně ani nepodařilo zjistit, jak velké pole vlastně je, když to zhavaruje.

Děkuji za odpověď.

Asi bych ty variace neukládal (k čemu je vlastně potřebuješ ???)

To máte asi pravdu, přímým použitím by paměť nepřetekla. Jenže napsat kód, který první ty variace vytvoří do pole a až potom je využije, je mnohem přehlednější, než když je budu používat hned při vytváření.

 public static void main(String[] args) {
        var chars = "abcdefghijklmnop".toCharArray();
        int variations = 7;

        var length = chars.length;
        var list = new LinkedList<String>();
        StringBuilder out = new StringBuilder();

        for (int i = 0; i < variations; i++) out.append(chars[0]);

        top:
        while (true) {
            list.add(out.toString());
            if (list.size() % 10000 == 0) {
                append(list);
                list.clear();
            }
            for (int pos = variations - 1; pos >= 0; pos--) {
                char c = out.charAt(pos);
                int cPos = Arrays.binarySearch(chars, c);
                if (cPos < length - 1) {
                    // We can just increment this one and we're done
                    out.setCharAt(pos, chars[cPos + 1]);
                    continue top;
                } else {
                    // 9-> 10: Every 'lower' digit is reset to first (0).
                    out.setCharAt(pos, chars[0]);
                }
            }
            break;
        }
    }

    public static void append(List<String> combinations) {
        try {
            Files.write(Paths.get("combinations.txt"), String.join("\n", combinations).getBytes(),
                    StandardOpenOption.APPEND, StandardOpenOption.CREATE);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    } 

Ukladani do souboru combinations.txt. A nepotrebujes ani zadne gigabajty heapu. Jako mustr jsem pouzil jeden z tvych kodu, co jsi jsem dal. Ten ktery se mi zdal nejlepsi...

Mala chybicka, zapomnel jsem zapsat posledni davku kombinaci. Oprava:

 public static void main(String[] args) {
        var chars = "abcdefghijklmnop".toCharArray();
        int variations = 7;

        var length = chars.length;
        var list = new LinkedList<String>();
        StringBuilder out = new StringBuilder();

        for (int i = 0; i < variations; i++) out.append(chars[0]);

        top:
        while (true) {
            list.add(out.toString());
            if (list.size() % 10000 == 0) {
                append(list);
                list.clear();
            }
            for (int pos = variations - 1; pos >= 0; pos--) {
                char c = out.charAt(pos);
                int cPos = Arrays.binarySearch(chars, c);
                if (cPos < length - 1) {
                    // We can just increment this one and we're done
                    out.setCharAt(pos, chars[cPos + 1]);
                    continue top;
                } else {
                    // 9-> 10: Every 'lower' digit is reset to first (0).
                    out.setCharAt(pos, chars[0]);
                }
            }
            break;
        }
        append(list);
    }

    public static void append(List<String> combinations) {
        try {
            Files.write(Paths.get("combinations.txt"), String.join(System.lineSeparator(), combinations).getBytes(),
                    StandardOpenOption.APPEND, StandardOpenOption.CREATE);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    } 

Ted uz budou v souboru vsechny kombinace...

Zpět do poradny Odpovědět na původní otázku Nahoru

Build a Mobile Site
View Site in Mobile | Classic
Share by: