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
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.…
MichalDM 20.09.2023 15:33
MichalDM
Asi bych ty variace neukládal (k čemu je vlastně potřebuješ ???), ale každou hned "použil". Nějak mi…
dsa 20.09.2023 18:31
dsa
Asi bych ty variace neukládal (k čemu je vlastně potřebuješ ???) To máte asi pravdu, přímým použití…
MichalDM 24.09.2023 00:29
MichalDM
Uloz si je do souboru, ne do pameti a pak je cti rovnou ze souboru. Velikost hedne variace znas, tak…
Jan Fiala 24.09.2023 06:19
Jan Fiala
Uloz si je do souboru, ne do pameti a pak je cti rovnou ze souboru. To je velmi zajímavá myšlenka,…
MichalDM 24.09.2023 16:09
MichalDM
public static void main(String[] args) { var chars = "abcdefghijklmnop".toCharArray(); int variatio…
MaSo 24.09.2023 20:52
MaSo
Mala chybicka, zapomnel jsem zapsat posledni davku kombinaci. Oprava: public static void main(Stri… poslední
MaSo 25.09.2023 07:15
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