我有一系列具有以下结构的对象:
structure Disk
{
int UID;
String Computer;
}
计算机可能有一堆共享磁盘,并且可以在计算机之间共享磁盘。
我想找出所有计算机常用的所有磁盘。例如,我有计算机A,B和C;磁盘1,2和3。 磁盘阵列为{1,A},{1,B},{2,A},{2,B},{2,C},{3,A}。 我想要的结果应该是磁盘2,因为它出现在A,B和C上。
有没有一种有效的方法来实现这一目标?
有多个foreach循环,它是可以实现的,但绝对我想要一个更好的方法。我正在考虑像交集这样的操作,但是在PowerShell中没有找到它。
答案 0 :(得分:71)
假设$arr
是数组,您可以这样做:
$computers = $arr | select -expand computer -unique
$arr | group uid | ?{$_.count -eq $computers.count} | select name
一般来说,我会在Powershell中接近联合和交集:
$a = (1,2,3,4)
$b = (1,3,4,5)
$a + $b | select -uniq #union
$a | ?{$b -contains $_} #intersection
但是对于你所问的问题,上述解决方案效果很好,而不是关于术语标准定义中的并集和交集。
更新
我写了pslinq,它提供了Union-List
和Intersect-List
,有助于实现与Powershell的集合和交集。
答案 1 :(得分:12)
您也可以
$a = (1,2,3,4)
$b = (1,3,4,5)
Compare-Object $a $b -PassThru -IncludeEqual # union
Compare-Object $a $b -PassThru -IncludeEqual -ExcludeDifferent # intersection
如果$a
为空,则无效。
答案 2 :(得分:10)
对于集合减法(a - b):
$a | ?{-not ($b -contains $_)}
答案 3 :(得分:6)
虽然这在最早的版本中不起作用,但在更新的版本中,您可以直接调用.NET LINQ扩展函数,例如。
[system.linq.enumerable]::union([object[]](1,2,3),[object[]](2,3,4))
(如果没有强制转换为某种可枚举的类型,PowerShell会抛出一个"找不到重载"错误。)
这绝对适用于PowerShell V4和V5,绝对不会在V2中使用。我没有V3的系统。