在 Powershell 中,是否有比自定义对象更好的方法来 store/find n 维数组中的数据

In Powershell, is there a better way to store/find data in an n-dimensional array than a custom object

我发现自己不断面临以某种结构存储混合类型数据以供日后查找的需要。

对于最近的一个例子,我正在执行数据迁移,我将存储未知数量的条目的旧 UUID、新 UUID、源环境、目标环境和架构。

我一直在通过创建一个数组并为每一列数据插入 System.Objects 和 NoteProperty 成员来满足这一需求。

我觉得这是一种非常笨拙的方法,但我觉得我可能会受到 Powershell 功能的限制。例如,如果我需要找到使用特定模式的所有条目,我会编写一个 foreach 循环,将每个条目与匹配的模式名称粘贴到一个我可以 return 的全新数组中。我非常希望能够更轻松地搜索包含与特定值匹配的成员的所有对象、修改现有成员等。

是否有更好的内置数据结构可以满足我的需要,或者创建自定义对象是否正确?

作为参考,我正在做这样的事情来创建我的结构:

$objectArray= @();
foreach(thing to process){
   $tempObj = New-Object System.Object;
   $tempObj | Add-Member -MemberType NoteProperty -Name "membername" -Value xxxxx
   ....repeat for each member...
   $objectArray += $tempObj
}

如果我需要在其中找到一些东西,我必须:

$matchingObjs = @()
foreach ($obj in $objectArray){
    if($obj.thing -eq value){$matchingObjs += $obj}
}

这真的很糟糕,我知道必须有更优雅的方法。我对 powershell 还是很陌生,所以我不知道它有哪些实用程序可以帮助我。我正在使用 v5。

没有内置方法可以完成您的要求。一种方法是将您的数据分段到单独的哈希表中,这样您就可以通过公共键(例如 ID)轻松查找。

# Create a hastable for the IDs
$ids = @{};
foreach(thing to process){
    $ids.Add($uid, 'Value')
}

# Find the $uid exists
$keyExists = $ids.Keys -Contains $uid

# Find value of stored for $uid
$keyValue = $ids[$uid]

附带说明,您不必创建 Syste.Object,您可以简单地执行此操作:

$objectArray = @();

gci | % {
    $objectArray += @{
        'Key1' = 'Value 1'
        'Key2' = 'Value 2'
    }
}

如果你需要比较复杂的对象,你可以用@{}构建它们,然后在两个对象上使用 Compare-Object,只是另一个想法。

例如,这将得到两个不同目录的文件列表,并告诉我两个目录之间存在或不存在什么文件:

$packages = (gci $boxStarterRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages += (gci $boxStarterPrivateRepo -Recurse *.nuspec | Select-Object -ExpandProperty Name) -replace '.nuspec', ''
$packages = $packages | Sort-Object

Compare-Object $packages $done

对于 PowerShell 3.0,您可以使用 [PSCustomObject],这里是 an article on the different object creation methods

同时将数组设置为等于 foreach 循环的输出将比 repeatedly recreating 具有 += 的数组更有效。

$objectArray = foreach ($item in $collection) {
    [pscustomobject]@{
        "membername" = "xxxxx"
    }
}

Where-Object cmdlet 或 .where() 方法看起来像您在第二个循环中需要的。

$matchingObjs = $objectArray | Where-Object {$_.thing -eq "value"}

听起来您也可以使用 Where-Object/.where() 来过滤初始数据并创建一个与您正在寻找的内容相匹配的对象。例如:

$matchingObjs = $InputData |
    Where-Object {$_.thing -eq "value"} |
    ForEach-Object {
        [pscustomobject]@{
            "membername" = xxxxx
        }
    }

如果您的数据可以表示为键值对,那么 hashtable 将是最有效的,请参阅 about_Hash_Tables 了解更多信息。