从PowerShell数组中删除重复值

145

如何从PowerShell数组中删除重复项?

$a = @(1,2,3,4,5,5,6,7,8,9,0,0)
12个回答

254

使用Select-Object(别名为select)和 -Unique 开关;例如:

$a = @(1,2,3,4,5,5,6,7,8,9,0,0)
$a = $a | select -Unique

9
太容易了 :-(。在 PowerShell 2 中,如果你的数组已经排好序,你也可以使用 Get-Unique(或 gu)。 - Joey
2
Johannes,Get-Unique 在 v1 中可用 :) - Shay Levy
5
很酷,这个很好用,只是注意,如果你想简洁一点,它甚至可以缩短为“-u”。我会在命令行上使用select -u,但在代码中编写时,建议使用完整的PS措辞:Select-Object -Unique - papo
这只适用于单个数字吗?对于大量的数组列表似乎不起作用。 - EagleDev
这对我来说不起作用,它只保留了一个有重复值的数据,就像创建了一个重复项列表一样。 - Mike Q
1
只是提醒一下,select -unique 不考虑大小写敏感性,所以在很多情况下无法正常工作。sort -unique 是正确的方法,(尽管你最终会得到一个排序后的数组)。 - az1d

101

另一个选项是使用Sort-Object(其别名为sort,但仅适用于Windows),并带有-Unique开关,将排序和去重组合在一起:

$a | sort -unique

2
这也解决了我的下一个问题,即如何对其进行排序。谢谢! - Registered User
3
这一个看起来也稍微快了一点。 - Gneo Pompeo
请注意,这不会保留元素的顺序,例如 @("B", "a", "A") | sort -unique 会产生 A B - roxton
2
这是更好的答案。select -unique 不考虑大小写敏感性。 - az1d

26

如果您希望完全防弹,这是我的建议:

@('Apples', 'Apples ', 'APPLES', 'Banana') | 
    Sort-Object -Property @{Expression={$_.Trim()}} -Unique

输出:

Apples
Banana

使用Property参数首先对字符串进行Trim()处理,从而删除额外的空格,然后仅选择-Unique值。

有关Sort-Object的更多信息:

Get-Help Sort-Object -ShowWindow

1
很棒的答案。解决了我的问题,“Get-Unique”不起作用是因为空格。 - Kellen Stuart

10
$a | sort -unique

这个方法不区分大小写,因此可以删除具有不同大小写的重复字符串。解决了我的问题。

$ServerList = @(
    "FS3",
    "HQ2",
    "hq2"
) | sort -Unique

$ServerList

以上输出内容为:

FS3
HQ2

这对于具有多个成员的数组也适用良好。 - JoeRod

8

以下是如何从具有两个或更多属性的数组中获取唯一项。排序是关键,确保正确工作。否则,只会返回一个项目。

PowerShell脚本:

$objects = @(
    [PSCustomObject] @{ Message = "1"; MachineName = "1" }
    [PSCustomObject] @{ Message = "2"; MachineName = "1" }
    [PSCustomObject] @{ Message = "3"; MachineName = "1" }
    [PSCustomObject] @{ Message = "4"; MachineName = "1" }
    [PSCustomObject] @{ Message = "5"; MachineName = "1" }
    [PSCustomObject] @{ Message = "1"; MachineName = "2" }
    [PSCustomObject] @{ Message = "2"; MachineName = "2" }
    [PSCustomObject] @{ Message = "3"; MachineName = "2" }
    [PSCustomObject] @{ Message = "4"; MachineName = "2" }
    [PSCustomObject] @{ Message = "5"; MachineName = "2" }
    [PSCustomObject] @{ Message = "1"; MachineName = "1" }
    [PSCustomObject] @{ Message = "2"; MachineName = "1" }
    [PSCustomObject] @{ Message = "3"; MachineName = "1" }
    [PSCustomObject] @{ Message = "4"; MachineName = "1" }
    [PSCustomObject] @{ Message = "5"; MachineName = "1" }
    [PSCustomObject] @{ Message = "1"; MachineName = "2" }
    [PSCustomObject] @{ Message = "2"; MachineName = "2" }
    [PSCustomObject] @{ Message = "3"; MachineName = "2" }
    [PSCustomObject] @{ Message = "4"; MachineName = "2" }
    [PSCustomObject] @{ Message = "5"; MachineName = "2" }
)

Write-Host "Sorted on both properties with -Unique" -ForegroundColor Yellow
$objects | Sort-Object -Property Message,MachineName -Unique | Out-Host

Write-Host "Sorted on just Message with -Unique" -ForegroundColor Yellow
$objects | Sort-Object -Property Message -Unique | Out-Host

Write-Host "Sorted on just MachineName with -Unique" -ForegroundColor Yellow
$objects | Sort-Object -Property MachineName -Unique | Out-Host

输出:

Sorted on both properties with -Unique

Message MachineName
------- -----------
1       1          
1       2          
2       1          
2       2          
3       1          
3       2          
4       1          
4       2          
5       1          
5       2          


Sorted on just Message with -Unique

Message MachineName
------- -----------
1       1          
2       1          
3       1          
4       1          
5       2          


Sorted on just MachineName with -Unique

Message MachineName
------- -----------
1       1          
3       2  

Source: https://powershell.org/forums/topic/need-to-unique-based-on-multiple-properties/


对于一些你可能不知道头部的for循环(例如自动解析某些csv数据)- 使用Sort-Object * -unique。 - Sebastian Wiszowaty

4

如果列表已经排序,您可以使用 Get-Unique 命令:

 $a | Get-Unique

2
需要事先对列表进行排序。 - Johny Skovdal

3

通过我的方法,您可以完全删除重复值,只留下数组中仅出现一次的值。不过,不清楚这是否是原始问题的实际需求,但我无法在网上找到此解决方案的示例,因此在此提供。

$array=@'
Bananna
Apple
Carrot
Pear
Apricot
Pear
Bananna
'@ -split '\r\n'

($array | Group-Object -NoElement | ?{$_.count -eq 1}).Name

我非常喜欢这个答案,但它有一个很大的缺陷。如果有多个具有相同名称的元素,则所有这些元素都会丢失,而应该保留其中一个。这个修复方法是:($properties | Group-Object -NoElement).Name | Get-Unique - az1d

1
为了从数组中获得唯一的元素并保持它们的顺序,您可以使用.NET HashSet:
$Array = @(1, 3, 1, 2)
$Set = New-Object -TypeName 'System.Collections.Generic.HashSet[int]' -ArgumentList (,[int[]]$Array)

# PS> $Set
# 1
# 3
# 2

在需要保留每个项目的不区分大小写的第一次出现的情况下,最适合使用同时包含大写和小写项目的字符串数组:

$Array = @("B", "b", "a", "A")
$Set = New-Object -TypeName 'System.Collections.Generic.HashSet[string]' -ArgumentList ([string[]]$Array, [StringComparer]::OrdinalIgnoreCase)

# PS> $Set
# B
# a

对于其他类型,它的工作效果符合预期。

缩短的语法,与PowerShell 5.1及更高版本兼容:

$Array = @("B", "b", "a", "A")
$Set = [Collections.Generic.HashSet[string]]::new([string[]]$Array, [StringComparer]::OrdinalIgnoreCase)

$Array = @(1, 3, 1, 2)
$Set = [Collections.Generic.HashSet[int]]::new([int[]]$Array)

1
很多提供的答案都会给出错误的结果。 select -Unique 不区分大小写。 sort -Unique 可以按原始顺序排序,这可能是你想要的。
Will 给出了一个很好的答案,但它存在缺陷,因为它丢弃了所有重复的结果,但忘记保留其中一个结果。
这是我创建的一个版本,似乎完美地工作。它返回唯一的结果,并保留原始排序顺序。 ($properties | Group-Object -NoElement).Name | Get-Unique

1
无论您使用的是 Powershell 2.0 到 5.1 中的 SORT -UNIQUESELECT -UNIQUE 还是 GET-UNIQUE,所有给出的示例都是针对单列数组的。我尝试过在多列数组中实现去除重复行以保留跨这些列的单个行的唯一实例,但尚未成功,也没有开发出替代的脚本解决方案。相反,这些 cmdlet 只返回了在数组中出现一次的行,并删除了所有具有重复项的行。通常情况下,我需要在 Excel 的最终 CSV 输出中手动删除重复项才能完成报告,但有时我希望在删除重复项后继续使用 Powershell 中的数据。

这就是Where-Object派上用场的地方。您首先通过使用正确的where子句将列表缩小,然后将其管道传递给sort-object,选择一个或多个要排序的列,并为sort-object提供-unique。 - LPChip
1
@Christopher,请查看我的帖子以解决你的问题。考虑删除此答案以清理解决方案。 - Omzig

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