【问题标题】:Searching a hashtable and moving duplicates搜索哈希表并移动重复项
【发布时间】:2015-02-03 15:48:46
【问题描述】:

我有一个脚本用于计算垒球(实际上是任何运动)的比赛对决。该脚本使用循环式计算来创建对决,以便每支球队至少与对方球队交手一次。此特定脚本允许您输入团队数量和游戏数量。根据比赛的数量,您可能会让球队互相比赛 2 或 3 次。因此,我还让脚本反转对战以模拟主客场比赛,因此如果比赛超过一次,任何球队都不会在主场占据优势。

当显示最终输出时,我的问题就出现了。我没有意识到对于每场“比赛”(所有球队的一系列对决),一些球队在同一场比赛/周中被列出两次。我们不希望任何球队在同一周/比赛中打两次。 在脚本中,我获取了一组比赛并将它们转换为一个哈希表,其中将比赛分组为球队数/2。

如何重新排列存在重复值的哈希表值并将它们与另一个“游戏”交换以创建没有团队玩两次的游戏(见下文)?

# Show input box popup and return the value entered by the user. 
function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText) 
{
     Add-Type -AssemblyName Microsoft.VisualBasic
     return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText) 
}

#define numbers of teams and games maybe use fields later

$teams = Read-InputBoxDialog -Message "Number of teams:" -WindowTitle "Teams" -DefaultText "3"
if ($teams -eq "0") { Write-Host "You clicked Cancel" } 
elseif ([int]$teams -gt "2" -and [int]$teams -lt 13) { Write-Host -foreground yellow "$teams Teams" } 
else { Write-Host "You entered $teams which is higher than the 12 teams this was designed for" }


$fields = Read-InputBoxDialog -Message "Number of fields:" -WindowTitle "Teams" -DefaultText "2"
if ($fields -eq $null) { Write-Host "You clicked Cancel" } 
elseif ([int]$fields -gt "0" -and [int]$fields -lt "4") { Write-Host -foreground green "$fields Fields" }  
else { Write-Host "You entered $fields which is higher than the 3 fields this was designed for" }

$gamess= "0"
$allplay= [int]$teams-1
$gamess = Read-InputBoxDialog -Message "Number of Games:" -WindowTitle "Games" -DefaultText "12"
if ($gamess -eq 0) { Write-Host "No value specified" } 
elseif ([int]$gamess -lt $allplay) {Write-host -foreground red "You must have more than 2 minus the number of teams or there won't be enough matches" }
elseif ([int]$gamess -lt "34") { Write-Host -foreground cyan "$gamess Games" } 
else { Write-Host "You entered $gamess which is more than 3 times the number of teams" }

#build array of teams
$a= 1..$teams

#if teams is odd number add a bye team to symbolize a bye for the opponent, thus making the number of teams even again
if ($teams % 2 -eq 1){$a += "bye"}
$parts = $a.length/2

#functions for game and rotating arrays borrowed most of the code for this from: http://www.hanselman.com/blog/2008WindowScriptingGamesAdvancedPowerShellEvent7.aspx 
[array]$global:games = $nul
function rotateArray($a)
{
 $first, $rest = $a
 $a = $rest + $first
 return $a
}
#function for creating away matchups 1 at a time
function makeGamesA($a)
{
 $i = 0;
 while($i -lt $a.Length/2)
 {
  $global:games = $global:games + ($a[$i].ToString() + " v " + $a[$a.Length-1-$i].ToString())
  $i++
 }  
}
#function for creating home matchups one at a time
function makeGamesH($a)
{
 $i = 0;
 while($i -lt $a.Length/2)
 {
  $global:games = $global:games + ($a[$a.Length-1-$i].ToString() + " v " + $a[$i].ToString())
  $i++
 }  
}
#here we create X as the variable that decides whether this is an away or home game and run the matching function based on even or odd value.
$x = 1
$z = 0
while($z -lt $gamess)
{
 if ($z -eq [int]$x*($a.length-1)) {$x++}
 if ($x % 2 -eq 1) {makeGamesA($a)}
 else {makeGamesH($a)}
 # hold on to the first one
 
 $first, $rest = $a
 #rotate the rest
 $rest = rotateArray($rest)
 $a = [array]$first + $rest
 $z++
}
#Collect into long array of match ups
$a = [collections.arraylist]$global:games
#convert values into hash table for each game played 
$b = @{}
$count = 1
$a |% {$b[$count % $gamess] += @($_);$count++}
$b= $b.getEnumerator() | sort-object Name

# Setting formatting specifications for each column in a hash table:
$column1 = @{expression="Name"; width=10; `
label="Game"; alignment="left"}
$column2 = @{expression="Value"; width=40; `
label="Team Matchups: Home vs. Away"; alignment="right"}
$f= $b | Format-table $column1, $column2
#print it out on the screen.
$f
read-host -foreground cyan "press any key to when finished"

【问题讨论】:

    标签: arrays powershell hashtable


    【解决方案1】:

    所以如果我理解正确,你的意思是重复的比赛是第 1 队对第 2 队和第 2 队对第 1 队,对吗?如果是这样,想象下面的“匹配网格”。考虑第一行,第一个团队不会与自己匹配,但它会完成其余部分。在第 2 行,团队 2 不会再次与团队 1 匹配(重复)或自身,但它会完成其余部分,依此类推。

    |1|2|3|4|5|6 -+-+-+-+-+-+- 1|n|y|y|y|y|y -+-+-+-+-+-+- 2|n|n|y|y|y|y -+-+-+-+-+-+- 3|n|n|n|y|y|y -+-+-+-+-+-+- 4|n|n|n|n|y|y -+-+-+-+-+-+- 5|n|n|n|n|n|y -+-+-+-+-+-+- 6|n|n|n|n|n|n

    假设有 6 个团队,此代码将生成网格。它现在只是遍历数字,但您可以轻松地遍历团队列表而不是数字。而且,既然您已经采取措施确保团队人数为偶数,那么您就大功告成了!

    for($i=0; $i -lt 6; $i++){
        [string]$str = ""
        for($j=0; $j -lt 6; $j++){
            if($i -ge $j){ $str = "$str n" }
            else{ $str = "$str y" }
        }
        Write-Output "$str `n"
    }
    

    为了进一步细化团队与团队的列表,这里有一个示例。

    $teams = @("Packers","Raiders","Patriots","Seahawks","Browns","Cowboys")
    
    for($i=0; $i -lt $teams.Count; $i++){
        for($j=0; $j -lt $teams.Count; $j++){
            if($i -lt $j){
                Write-Output "$($teams[$i]) vs. $($teams[$j])"
            }
        }
    }
    
    Packers vs. Raiders
    Packers vs. Patriots
    Packers vs. Seahawks
    Packers vs. Browns
    Packers vs. Cowboys
    Raiders vs. Patriots
    Raiders vs. Seahawks
    Raiders vs. Browns
    Raiders vs. Cowboys
    Patriots vs. Seahawks
    Patriots vs. Browns
    Patriots vs. Cowboys
    Seahawks vs. Browns
    Seahawks vs. Cowboys
    Browns vs. Cowboys
    

    【讨论】:

    • 不完全是。我所说的重复是指在一场比赛中出现两次的球队的任何实例: 当前脚本的示例输出 比赛 1:[1 v 2, 3 v 4, 1 v 5] 您会注意到第 1 场比赛的比赛在我们的例子中,在同一个游戏系列中两次,每场比赛是一周,所以第 1 队在那一周会打两次。同样在当前脚本中,我故意颠倒团队分配以创建“客场与主场”计划。所以 1v2 和 2v1 实际上是同一个游戏,只是在不同的地点玩。
    【解决方案2】:

    我想了想,然后在纸上画出了对决,但我不明白为什么我永远不会让一个团队在一个系列赛中出现两次。然后我意识到我从原始数组到哈希表的转换导致对战的排序不同,从而导致重复(为了澄清,请参阅我对坎贝尔回答的评论)。我决定对其进行更改,并让它将数组转换为另一个数组,使用团队数除以 2 对比赛进行分组。

    function Split-Collection {
            [CmdletBinding()]
            param(
                [Parameter(ValueFromPipeline=$true)] $Collection,
                [Parameter(Mandatory=$true)][ValidateRange(1, 247483647)][int] $Count
            )
            begin {
                $Ctr = 0
                $Arrays = @()
                $TempArray = @()
            }
            process {
                if (++$Ctr -eq $Count) {
                    $Ctr = 0
                    $Arrays += , @($TempArray + $_)
                    $TempArray = @()
                    return
                }        
                $TempArray += $_ 
            }
            end {
            if ($TempArray) { $Arrays += , $TempArray }
            $Arrays
          }
        }
    
        #split up the array output the values to the form variable.
    
        $b = $a | Split-collection -Count $parts | %{ $_ -join ' | '}

    我的输出现在看起来像这样:这是所需的效果。每场比赛都是可以同时进行的所有比赛的代表。

    第 20 场比赛:1 对 4 | 5 对 3 |再见 v 2

    第 21 场比赛:1 对 5 |再见 v 4 | 2 对 3

    第 22 场比赛:再见 v 1 | 5 对 2 | 4 对 3

    第 23 场比赛:2 对 1 |再见 v 3 | 5 对 4

    第 24 场比赛:3 对 1 | 2 对 4 |再见 5

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-21
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 2012-10-12
      • 2013-10-22
      • 2013-04-27
      • 2010-09-08
      相关资源
      最近更新 更多