Jak wygenerować wszystkie możliwe kombinacje

0
Folder Prey has 
    "Deer.txt",
    "Antelope.txt",
    "Rabbit.txt"  
Folder Predator has 
    "Shark.txt",
    "Bear.txt",
    "Cougar.txt"  
Folder Habitat has 
    "Forest.txt",
    "Ocean.txt",
    "Desert.txt"

Jak wygenerować wszystkie 27 możliwych kombinacji przy użyciu pliku .bat? Problem polega na tym, że liczba folderów nie jest statyczna. Ktoś może później dodać Folder Food lub usunąć Folder Habitat. Czy można by zapisać plik .bat, aby sobie z tym poradzić?

Dane wyjściowe będą:

Deer_Shark_Forest
Deer_Shark_Ocean
Deer_Shark_Desert
Deer_Bear_Forest
Deer_Bear_Ocean
Deer_Bear_Desert
Deer_Cougar_Forest
Deer_Cougar_Ocean
Deer_Cougar_Desert
Antelope_Shark_Forest
Antelope_Shark_Ocean
Antelope_Shark_Desert
Antelope_Bear_Forest
Antelope_Bear_Ocean
Antelope_Bear_Desert
Antelope_Cougar_Forest
Antelope_Cougar_Ocean
Antelope_Cougar_Desert
Rabbit_Shark_Forest
Rabbit_Shark_Ocean
Rabbit_Shark_Desert
Rabbit_Bear_Forest
Rabbit_Bear_Ocean
Rabbit_Bear_Desert
Rabbit_Cougar_Forest
Rabbit_Cougar_Ocean
Rabbit_Cougar_Desert

Zapewniam cię, że to nie jest zadanie domowe. Chciałbym napisać to jako plik wsadowy.

Rick Tan
źródło
Co rozumiesz przez „wszystkie możliwe kombinacje”? Proszę edytować swoje pytanie przedstawiają przykładowe wyjście i zawierać co próbowałeś do tej pory.
Ben N
1
To bardzo brzmi jak zadanie domowe.
Run5k,
Próbowałem zagnieżdżać pętle For, ale ma to ograniczenia. Liczba folderów jest określana w czasie kompilacji, a nie w czasie wykonywania. Chciałbym mieć możliwość dodawania lub usuwania folderów.
Rick Tan,
Przykład zawiera 3 foldery po 3 elementy lub 27 kombinacji.
Rick Tan,
Folder zawiera pliki. Wyświetlana jest lista wartości tekstowych. Proszę dokładnie wyjaśnić, jakie jest źródło.
fixer1234

Odpowiedzi:

2

Możesz to zrobić za pomocą następującego pliku wsadowego:

@echo off
setlocal enabledelayedexpansion
set first_pass=yes
copy nul temp2.txt > nul
for /d %%D in (*) do (
    for %%F in ("%%D"\*) do (
        if !first_pass! == yes (
            echo %%~nF >> temp2.txt
        ) else (
            for /f "delims=" %%L in (temp1.txt) do (
                echo %%~nF_%%L >> temp2.txt
            )
        )
    )
    set first_pass=no
    del temp1.txt 2> nul
    rename temp2.txt temp1.txt
)

Spowoduje to utworzenie pliku o nazwie temp1.txt. (Oczywiście skrypt można w trywialny sposób zmodyfikować, aby używał innej nazwy pliku i / lub wyświetlał wyniki na ekranie.) Oto wynik, który otrzymałem:

Antelope_Bear_Desert
Antelope_Bear_Forest
Antelope_Bear_Ocean
Antelope_Cougar_Desert
Antelope_Cougar_Forest
Antelope_Cougar_Ocean
Antelope_Shark_Desert
Antelope_Shark_Forest
Antelope_Shark_Ocean
Deer_Bear_Desert
Deer_Bear_Forest
Deer_Bear_Ocean
Deer_Cougar_Desert
Deer_Cougar_Forest
Deer_Cougar_Ocean
Deer_Shark_Desert
Deer_Shark_Forest
Deer_Shark_Ocean
Rabbit_Bear_Desert
Rabbit_Bear_Forest
Rabbit_Bear_Ocean
Rabbit_Cougar_Desert
Rabbit_Cougar_Forest
Rabbit_Cougar_Ocean
Rabbit_Shark_Desert
Rabbit_Shark_Forest
Rabbit_Shark_Ocean

Uwagi:

  • Oczywiście wykorzystuje to *symbol wieloznaczny, więc kolejność danych wyjściowych zależy od kolejności, w której system Windows rozwija symbol wieloznaczny. W moim systemie dane alfabetyczne pozycje katalogu *są rozwijane w kolejności alfabetycznej. Może to być inne w systemach używających języków innych niż angielski i / lub może być zmieniane przez ustawienie konfiguracji. Dla celów następnych dwóch pocisków założę, że użyto kolejności alfabetycznej.
  • W każdym folderze nazwy są uporządkowane alfabetycznie; np. Antylopa przed jeleniem itp., Niedźwiedź przed kuguarem itp., itd ...
  • Zgodnie z żądanym wyjściem określonym w pytaniu, foldery są wyprowadzane w odwrotnej kolejności alfabetycznej; tj. Prey_Predator_Habitat.
  • Każde z powyższych można zmienić (choć nie elegancko).


  • setlocal enabledelayedexpansion pozwala nam obsługiwać zmienne w pętlach.
  • copy nul temp2.txt > nultworzy drugi tymczasowy plik roboczy. > nulHamuje normalny 1 file(s) copied.komunikat o stanie.
  • for /d %%D in (*) dozapętla wszystkie foldery w bieżącym katalogu. Zmienna %%Dbędzie kolejno przyjąć wartości Habitat, Predatororaz Prey- czy cokolwiek foldery są w bieżącym katalogu po uruchomieniu pliku wsadowego.
  • for %%F in ("%%D"\*) dozapętla wszystkie pliki w katalogu %%D; tzn. katalog, na który patrzymy obecnie z zewnętrznej pętli. Zmienna %%Fbędzie kolejno wziąć na wartościach takich jak Habitat\Desert.txt, Habitat\Forest.txti Habitat\Ocean.txt. Cudzysłowy pozwalają na to, nawet jeśli nazwa katalogu zawiera spacje.

    Jeśli w folderze znajdują się inne pliki, zostaną one również uwzględnione. Jeśli chcesz patrzeć tylko na .txtpliki, zmień forinstrukcję na for %%F in ("%%D"\*.txt) do.

  • !first_pass!jest tylko zmienną first_pass. Normalnie byłby napisany %first_pass%, ale musimy użyć tej składni, ponieważ jesteśmy w pętli. (Działa to tylko dlatego, że włączyliśmy go, z setlocal enabledelayedexpansion.)
  • first_passjest yespodczas przetwarzania pierwszego katalogu; tj Habitat. W tym przypadku po prostu zapisujemy nazwę temp2.txtpliku; więc po zakończeniu for %%F in ("%%D"\*) dopętli temp2.txt będzie zawierać
    Desert 
    Forest
    Ocean
    dlatego %%~nF ocenia się tylko do pliku bazy n ame części ścieżki w pliku %%F. Jeśli chcesz dołączyć do .txte x napięć, użyj %%~nxFzamiast %%~nF.
  • Ostrzeżenie spoilera: kiedy wykonujemy zewnętrzny ( for /d %%D) po raz drugi i trzeci (itp.), first_passJest no i temp1.txtjest temp2.txtz poprzedniego przejścia.
  • Tak więc w drugim i trzecim (itd.) Przejściu wykonujemy for /f "delims=" %%L in (temp1.txt) do, który zapętla się przez linie w temp1.txt, ustawiając %%Lsię na zawartość linii. "delims="to ciąg opcji, który określa, że ​​wiersze nie powinny być dzielone na słowa. Umożliwia to działanie tego pliku wsadowego, nawet jeśli nazwy plików zawierają spacje.
  • Na przykład, w drugim przejściu ( %%D= Predator) zewnętrznej pętli, kiedy robimy pierwszy przebieg ( %%F= Predator\Bear.txt) drugiej pętli, temp1.txtjest jak pokazano powyżej dla temp2.txti temp2.txtjest pusty.
  • Robimy dla każdej linii ( %%L) from temp1.txt, echo %%~nF_%%L >> temp2.txtktóra zapisuje bieżącą nazwę pliku, znak podkreślenia _i bieżącą linię (from temp1.txt) do temp2.txt(dołączanie). Zatem po pierwszym przejściu ( Bear) drugiej pętli, zawierającej pełny przebieg trzeciej pętli, temp2.txt będzie zawierać
    Bear_Desert 
    Bear_Forest
    Bear_Ocean
    CougarDołączone zostanie drugie przejście ( ) drugiej pętli
    Cougar_Desert 
    Cougar_Forest
    Cougar_Ocean
    do temp2.txt, i tak dalej.
  • Zanim dotrzemy do trzeciego przejścia ( %%D= Prey) zewnętrznej pętli, temp1.txtjest temp2.txtz poprzedniego przejścia, zawierającego dziewięć linii (z których sześć pokazano powyżej). Potem dzieje się to samo (z różnymi wartościami) jak poprzednio; %%Fustawia się na Prey\Antelope.txt, a więc każdy wiersz temp1.txtjest kopiowany temp2.txt z wcześniej przygotowanym Antelope_, i otrzymujemy
    Antelope_Bear_Desert 
    Antelope_Bear_Forest
    Antelope_Bear_Ocean Antelope_Cougar_Desert
    Antelope_Cougar_Forest
  • Jak zapowiadał, kiedy skończymy drugą pętlę, i dostać się do końca pierwszej pętli, ustawiamy first_passsię no, usuń bieżący temp1.txt (jeśli w ogóle, a jeżeli jeszcze nie istnieje, tłumić komunikat o błędzie) i zmienić nazwę temp2.txtna temp1.txt.

W rezultacie otrzymujemy plik o długości 27 linii (Num ( Habitat) × Num ( Predator) × Num ( Prey)). Możesz dodawać i usuwać foldery i pliki, ponieważ w skrypcie nic nie jest zakodowane na stałe - nawet liczba folderów.

  • Jeśli istnieje folder (np. Job_Titles), Który nie zawiera plików, nie będzie danych wyjściowych (ponieważ 3 × 0 × 3 × 3 = 0). W rzeczywistości w tym przypadku powyższy plik wsadowy generuje wiele komunikatów o błędach oraz albo pusty temp1.txtplik (oczekiwane zachowanie), albo w ogóle nie ma pliku. Można to oczywiście naprawić.
  • Ten skrypt został zaprojektowany do obsługi nazw plików lub katalogów zawierających spacje i został przetestowany w tej sytuacji (i wydaje się działać poprawnie), ale mogą istnieć pewne przypadki krawędzi, których nie wziąłem pod uwagę.
  • Nieuchronnie wynik będzie dwuznaczny, jeśli którakolwiek z nazw plików zawiera _(podkreślenie). Na przykład Antelope_Mountain_Lion_Forestjest niejednoznaczny.
G-Man
źródło
1

Możesz użyć PowerShell:

$categories = gci -Directory | % {$_.Name}
Function AddCombos([int]$catPos, $root) {
    gci ".\$($categories[$catPos])\*.txt" | % {
        $memberTitle = [IO.Path]::GetFileNameWithoutExtension($_.Name)
        If ($catPos -eq ($categories.Length - 1)) {
            $root + $memberTitle
        } Else {
            AddCombos ($catpos + 1) ($root + $memberTitle + '_')
        }
    }
}
AddCombos 0 ''

Po pierwsze, ten skrypt pobiera nazwy wszystkich kategorii (np. „Zdobycz”) i umieszcza je na $categoriesliście. Następnie definiuje funkcję rekurencyjną. AddCombospobiera wszystkie pliki w kategorii zindeksowane przez $catPos. Jeśli nie ma go w ostatniej kategorii, wyświetla ukończony ciąg. W przeciwnym razie wywołuje się po dodaniu bieżącego elementu członkowskiego (np. „Jeleń”) do ciągu w toku i inkrementacji, $catPosaby wskazać, że należy przejrzeć następną kategorię. Po zdefiniowaniu tej funkcji skrypt wywołuje ją od pierwszej kategorii (indeks 0) i z pustym ciągiem znaków w trakcie pracy.

Pamiętaj, że kolejność kategorii jest ustalana alfabetycznie. Ponieważ nazwy folderów nie są używane w danych wyjściowych, możesz nazwać je w taki sposób, aby były tworzone w żądanej kolejności. Skrypt używa tytułów plików tekstowych w danych wyjściowych, ale jeśli chcesz kontrolować ich kolejność, zmieniając nazwy plików, możesz zmienić $memberTitle =wiersz na:

$memberTitle = (gc $_)[0]

To zajmuje pierwszy wiersz zawartości każdego pliku zamiast jego tytułu.

Ten skrypt może obsługiwać dowolną liczbę kategorii i dowolną liczbę członków w każdej kategorii.

Aby go uruchomić, zapisz go jako .ps1plik i postępuj zgodnie z instrukcjami w sekcji Włączanie skryptów wiki tagów PowerShell . Następnie możesz uruchomić go z pliku wsadowego takiego jak ten:

powershell .\myscript.ps1
Ben N.
źródło
0
@echo off
    setlocal enableextensions disabledelayedexpansion

    for %%t in ("%temp%\%random%%random%%random%.tmp") do (
        >"%%~ft" echo(*
        for /d %%d in (*) do >nul 2>&1 dir /a-d "%%d" && for /f "tokens=* delims=*" %%l in ('
            type "%%~ft" ^& ^>"%%~ft" break
        ') do for %%f in ("%%d\*") do (
            >>"%%~ft" (if "%%~l"=="" (echo(%%~nf) else (echo %%l_%%~nf))
        )
    ) & type "%%~ft" & del "%%~ft"

Wygeneruje plik tymczasowy (do którego odwołuje się %%t), w którym konkatenuje linie wyjściowe.

Dla każdego katalogu ( %%d) plik tymczasowy jest odczytywany, czyszczony, a dla każdej linii ( %%l) w pliku tymczasowym jest ponownie powtarzany z każdym plikiem ( %%f) w bieżącym folderze połączonym

Po połączeniu wszystkich nazw plików plik tymczasowy jest wysyłany do konsoli i usuwany.

MC ND
źródło