如何生成所有可能的组合

如何生成所有可能的组合
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"

如何使用 .bat 文件生成所有 27 种可能的组合?棘手的部分是文件夹的数量不是静态的。有人可能会在以后添加文件夹 Food,或删除文件夹 Habitat。可以编写 .bat 文件来处理这个问题吗?

输出结果为:

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

向你保证这不是家庭作业问题。我想将其写成批处理文件。

答案1

您可以使用以下批处理文件执行此操作:

@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
)

这将创建一个名为的文件temp1.txt。(当然,可以简单地修改脚本以使用不同的文件名和/或在屏幕上显示结果。)这是我得到的输出:

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

笔记:

  • 显然,这使用了*通配符,因此输出的顺序取决于 Windows 扩展通配符的顺序。在我的系统上,给定字母目录条目, *将按字母顺序展开。在使用英语以外的语言的系统上,这可能会有所不同,并且/或者可以通过配置设置进行更改。为了接下来的两个要点,我将假设使用字母顺序。
  • 在每个文件夹中,名称都按字母顺序排列;例如,羚羊在鹿之前,等等……,熊在美洲狮之前,等等……
  • 根据您在问题中指定的期望输出,文件夹输出为撤销字母顺序;即 Prey_Predator_Habitat。
  • 以上任何一种情况都可以改变(尽管不太优雅)。


  • setlocal enabledelayedexpansion让我们在循环中处理变量。
  • copy nul temp2.txt > nul创建第二个临时工作文件。这> nul将隐藏正常1 file(s) copied.状态消息。
  • for /d %%D in (*) do循环遍历当前目录中的所有文件夹。运行批处理文件时,变量%%D将依次取值 HabitatPredator和— 或当前目录中的任何文件夹。Prey
  • for %%F in ("%%D"\*) do循环遍历目录中的所有文件%%D;即我们当前从外层循环查看的目录。变量%%F将按顺序取值,例如 Habitat\Desert.txtHabitat\Forest.txtHabitat\Ocean.txt。即使目录名称包含空格,引号也能使此操作正常工作。

    如果文件夹中还有其他文件,它们也会被包含。如果您只想查看.txt文件,请将for语句更改为for %%F in ("%%D"\*.txt) do

  • !first_pass!就是变量first_pass。它通常会被写成%first_pass%,但我们需要使用这种语法,因为我们处于循环中。(这只因为我们启用了它,所以才有效,用setlocal enabledelayedexpansion。)
  • first_passyes在我们处理第一个目录时;即Habitat。在这种情况下,我们只是将文件名写入文件temp2.txt;因此,当for %%F in ("%%D"\*) do循环完成时,temp2.txt 将包含
    沙漠
    森林
    海洋
    因为%%~nF 仅评估基础文件n文件名的一部分%%F。如果你想包含.txteX紧张,用%%~nxF代替%%~nF
  • for /d %%D剧透警告:当我们第二次和第三次(等等)执行外部( )时,first_passno 并且temp1.txttemp2.txt来自上一次传递的。
  • 因此,在第二次和第三次(等等)传递时,我们执行for /f "delims=" %%L in (temp1.txt) do,循环遍历线在 中temp1.txt,设置%%L为行的内容。 "delims="选项字符串,指定行不应被拆分成单词。这样即使文件名包含空格,此批处理文件也能正常工作。
  • 例如,在外循环的第二遍(%%D= )中,当我们执行第二个循环的 Predator第一遍(%%F= )时,如上所示,并且为空。Predator\Bear.txttemp1.txttemp2.txttemp2.txt
  • 对于来自 的每一行 ( %%L) temp1.txt,我们执行echo %%~nF_%%L >> temp2.txt,将当前文件名、下划线_和当前行 (来自temp1.txt)写入temp2.txt(追加)。因此,在第二个循环的第一遍 ( Bear) 之后,包括第三个循环的完整运行,temp2.txt 将包含
    熊_沙漠
    熊_森林
    熊_海洋
    Cougar第二个循环的 第二遍( )将附加
    美洲狮沙漠
    美洲狮森林
    美洲狮海洋
    temp2.txt等等。
  • 当我们到达外循环的 第三遍( %%D= )时,是来自上一遍的,包含九行(其中六行如上所示)。然后发生与之前相同的事情(使用不同的值); 设置为,因此每一行都被复制到 前面,我们得到 Preytemp1.txttemp2.txt%%FPrey\Antelope.txttemp1.txttemp2.txtAntelope_
    羚羊熊沙漠
    羚羊熊森林
    羚羊熊海洋 羚羊_美洲狮_沙漠
    羚羊_美洲狮_森林
  • 正如预示的那样,当我们完成第二个循环并到达第一个循环的末尾时,我们将其设置first_passno,删除当前temp1.txt (如果有;如果尚不存在,则隐藏错误消息),并重命名temp2.txttemp1.txt

因此,我们最终得到一个长度为 27 行的文件 (Num( Habitat) × Num( Predator) × Num( Prey))。您可以添加和删除文件夹和文件,因为脚本中没有任何内容是硬编码的 — 甚至文件夹的数量也没有。

  • 如果有一个文件夹(例如Job_Titles)不包含任何文件,则不会有任何输出(因为 3 × 0 × 3 × 3 = 0)。事实上,在这种情况下,上述批处理文件会产生一堆错误消息,并且会产生一个空temp1.txt文件(预期行为)或根本没有文件。当然,这可以修复。
  • 该脚本被设计用于处理包含空格的文件或目录名称,并且已经在这种情况下进行了测试(并且似乎工作正常),但可能存在一些我没有考虑到的特殊情况。
  • 不可避免的是,如果任何文件名包含_(下划线),输出将会产生歧义。例如,Antelope_Mountain_Lion_Forest会产生歧义。

答案2

您可以使用 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 ''

首先,此脚本获取所有类别的名称(例如“Prey”)并将它们放入列表中$categories。然后它定义一个递归函数。AddCombos获取由 索引的类别中的所有文件$catPos。如果它不在最后一个类别上,它将输出完成的字符串。否则,它会在将当前成员(例如“Deer”)添加到正在进行的字符串并递增$catPos以指示应查看下一个类别后调用自身。定义该函数后,脚本从第一个类别(索引 0)开始调用它,并使用空字符串作为正在进行的工作。

请注意,类别的顺序是按字母顺序确定的。由于文件夹名称未在输出中使用,因此您可以按所需的顺序命名它们。脚本在输出中使用文本文件的标题,但如果您想通过重命名文件来控制这些顺序,您可以将该行更改$memberTitle =为:

$memberTitle = (gc $_)[0]

这将获取每个文件内容的第一行而不是其标题。

该脚本可以处理任意数量的类别以及每个类别中的任意数量的成员。

要运行它,请将其保存为.ps1文件,然后按照启用脚本部分中的说明进行操作PowerShell 标签 wiki。然后您可以从批处理文件运行它,如下所示:

powershell .\myscript.ps1

答案3

@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"

它将生成一个临时文件(由引用%%t)来连接输出行。

对于每个目录 ( %%d),都会读取、清除临时文件,并且对于%%l临时文件中的每一行 ( ),都会再次回显,并将%%f当前文件夹下的每个文件 ( ) 连接起来

一旦所有文件名都被连接起来,临时文件就会被发送到控制台并被删除。

相关内容