如何在 Powershell 中为多维数组执行带有 where 子句的 foreach 循环?
How do I do foreach loop with a where clause for a multidimensional array in Powershell?
例如
$people = @(
@('adam', '24', 'M')
@('andy', '20', 'M')
@('alex', '30', 'M')
@('ava', '25', 'F')
)
foreach($person in $people | where ($person[1] -lt '25') -and ($person[2] -eq 'M'))
这应该 select adam
和 andy
...
您应该在 Where-Object
语句中使用的语法是:
$people = @(
@('adam', '24', 'M'),
@('andy', '20', 'M'),
@('alex', '30', 'M'),
@('ava', '25', 'F')
)
$people | Where-Object { $_[1] -lt '25' -and $_[2] -eq 'M' } | ForEach-Object { $_[0] }
# Results in:
#
# adam
# andy
或者使用带有 if
语句的传统 foreach
循环:
foreach($array in $people) {
if($array[1] -lt 25 -and $array[2] -eq 'M') {
$array[0]
}
}
然而,正如上一个答案中所建议的那样,hash table 可能更适合这个(即使语法有点复杂):
$people = @{
M = @{
24 = 'adam'
20 = 'andy'
30 = 'alex'
}
F = @{
25 = 'ava'
}
}
$people['M'][$people['M'].Keys -lt 25]
当然可以使用涉及ForEach-Object的答案。唯一可能的问题(取决于您要对该数据执行的操作)是 ForEach-Object 将单独执行每条数据记录。
另一种方法是专门创建您想要的对象,然后使用标准的 foreach()。
$people = @(
@('adam', '24', 'M')
@('andy', '20', 'M')
@('alex', '30', 'M')
@('ava', '25', 'F')
)
$filteredPeople = $people | Where-Object { $_[1] -lt '25' -and $_[2] -eq 'M'}
foreach($person in $$filteredPeople) {
#stuff
}
这将对整个对象执行相同的功能。
很好的解决了你的问题
让我提供一个替代方案,它使用 PowerShell v5+ 自定义 class
来为您的数组实例建模,这使得描述性更强,并且 type-safe 可以访问每个人的属性:
# Define a [Person] class with a constructor that fills all properties.
class Person {
[string] $Name
[int] $Age
[char] $Sex
Person([string] $name, [int] $age, [char] $sex) {
$this.Name = $name; $this.Age = $age; $this.Sex = $sex
}
}
# Create an array of [Person] instances.
$people = @(
[Person]::new('adam', '24', 'M')
[Person]::new('andy', '20', 'M')
[Person]::new('alex', '30', 'M')
[Person]::new('ava', '25', 'F')
)
# Filter the array via the .Where() array method.
$people.Where({ $_.Age -lt 25 -and $_.Sex -eq 'M' })
输出:
Name Age Sex
---- --- ---
adam 24 M
andy 20 M
如果您只对 .Name
属性 值感兴趣,只需将 .Name
附加到上面的最后一个命令,即 returns 数组 'adam', 'andy'
,由 PowerShell 的 member-access enumeration 功能提供。
请注意,使用 .Where()
array method, which - for collections already in memory - is a more efficient alternative to the Where-Object
cmdlet; that said, a foreach
statement 效果最佳。
例如
$people = @(
@('adam', '24', 'M')
@('andy', '20', 'M')
@('alex', '30', 'M')
@('ava', '25', 'F')
)
foreach($person in $people | where ($person[1] -lt '25') -and ($person[2] -eq 'M'))
这应该 select adam
和 andy
...
您应该在 Where-Object
语句中使用的语法是:
$people = @(
@('adam', '24', 'M'),
@('andy', '20', 'M'),
@('alex', '30', 'M'),
@('ava', '25', 'F')
)
$people | Where-Object { $_[1] -lt '25' -and $_[2] -eq 'M' } | ForEach-Object { $_[0] }
# Results in:
#
# adam
# andy
或者使用带有 if
语句的传统 foreach
循环:
foreach($array in $people) {
if($array[1] -lt 25 -and $array[2] -eq 'M') {
$array[0]
}
}
然而,正如上一个答案中所建议的那样,hash table 可能更适合这个(即使语法有点复杂):
$people = @{
M = @{
24 = 'adam'
20 = 'andy'
30 = 'alex'
}
F = @{
25 = 'ava'
}
}
$people['M'][$people['M'].Keys -lt 25]
当然可以使用涉及ForEach-Object的答案。唯一可能的问题(取决于您要对该数据执行的操作)是 ForEach-Object 将单独执行每条数据记录。
另一种方法是专门创建您想要的对象,然后使用标准的 foreach()。
$people = @(
@('adam', '24', 'M')
@('andy', '20', 'M')
@('alex', '30', 'M')
@('ava', '25', 'F')
)
$filteredPeople = $people | Where-Object { $_[1] -lt '25' -and $_[2] -eq 'M'}
foreach($person in $$filteredPeople) {
#stuff
}
这将对整个对象执行相同的功能。
让我提供一个替代方案,它使用 PowerShell v5+ 自定义 class
来为您的数组实例建模,这使得描述性更强,并且 type-safe 可以访问每个人的属性:
# Define a [Person] class with a constructor that fills all properties.
class Person {
[string] $Name
[int] $Age
[char] $Sex
Person([string] $name, [int] $age, [char] $sex) {
$this.Name = $name; $this.Age = $age; $this.Sex = $sex
}
}
# Create an array of [Person] instances.
$people = @(
[Person]::new('adam', '24', 'M')
[Person]::new('andy', '20', 'M')
[Person]::new('alex', '30', 'M')
[Person]::new('ava', '25', 'F')
)
# Filter the array via the .Where() array method.
$people.Where({ $_.Age -lt 25 -and $_.Sex -eq 'M' })
输出:
Name Age Sex
---- --- ---
adam 24 M
andy 20 M
如果您只对 .Name
属性 值感兴趣,只需将 .Name
附加到上面的最后一个命令,即 returns 数组 'adam', 'andy'
,由 PowerShell 的 member-access enumeration 功能提供。
请注意,使用 .Where()
array method, which - for collections already in memory - is a more efficient alternative to the Where-Object
cmdlet; that said, a foreach
statement 效果最佳。