PowerShell中的并集和交集?

59
我有一个以下结构的对象数组:
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中没有找到这个操作。


1
我建议将标题更改为“PowerShell中的并集、交集和差集/集合减法”。这样我们就可以在一个地方找到所有的集合操作。 - Mehrdad Mirreza
1
根据这里的问题和建议,我创建了一个PowerShell函数来执行对象的并集、交集和差集。请查看:https://sqljana.wordpress.com/2015/09/23/perform-set-operations-union-intersection-minus-complement-using-powershell/ - Jana Sattainathan
5个回答

104

假设 $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-ListIntersect-List来帮助在Powershell中实现集合的并集和交集。


厉害啊,像HashTable这样的键控集合会如何使用这些一行代码呢? - Bastl
1
很棒的帖子--应该有一个标准库来提供类似的功能。PowerShell 的 lodash.. - ferr
4
为了完整性,您可以使用以下代码获取 $a 和 $b 之间的差异: $a | ?{$b -notcontains $_} #difference - Simon Ejsing
有人能给我提供一个 Technet 链接,展示 ?{...} 结构的定义和/或示例吗? - northern-bradley
? 是 Where-Object 的别名,所以 ? {} 等同于 Where-Object -FilterScript {...}。 - Sigitas

27

你还可以这样做

$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为null,则无法运行。


1
可以将 $null 添加到数组中。$a = 1,2,3,4,$null - Nathan Hartley

15

对于集合减法 (a - b):

$a | ?{-not ($b -contains $_)}


15
还有一个 -notcontains。 - Nathan Hartley
2
Narthan 为人们节省时间并在下次写出来:)$a | ?{$b -notcontains $_} - Yannic Hamann

10

虽然在早期版本中这种方法行不通,但在更近期的版本中,您可以直接调用.NET LINQ扩展函数,例如:

[system.linq.enumerable]::union([object[]](1,2,3),[object[]](2,3,4))

如果没有将其转换为可枚举类型,PowerShell会抛出“找不到重载”错误。

这在 PowerShell V4 和 V5 中肯定有效,但在 V2 中肯定无效。我手头没有安装 V3 的系统。


2

我注意到没有人回答你关于计算机a、b、c的具体例子,它们附带编号为1、2、3的磁盘。

给出了三个集合的交集、并集和差异的代码和输出。

代码

$a = @(1, 2, 3)
$b = @(1, 2)
$c = @(2)

'Intersection $a ⋂ $b ⋂ $c'
$a | Where-Object {$_ -In $b} | Where-Object {$_ -In $c}

'Union $a ⋃ $b ⋃ $c'
$a + $b + $c | Select-Object -Unique

'Set difference $a - $b - $c (items in $a but not $b or $c)'
$a | Where-Object {$_ -NotIn $b} | Where-Object {$_ -NotIn $c}

输出

Intersection $a$b$c
2
Union $a$b$c
1
2
3
Set difference $a - $b - $c (items in $a but not $b or $c)
3

1
精彩的帖子..正是我想要的.. - veenz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接