2

I'd like to move hashtables from one array to another.

Assuming that I have an array of hashtables:

PS> $a = @( @{s='a';e='b'}, @{s='b';e='c'}, @{s='b';e='d'} )

Name                           Value
----                           -----
s                              a
e                              b
s                              b
e                              c
s                              b
e                              d

I can copy a selected set to another array:

PS> $b = $a | ? {$_.s -Eq 'b'}

Name                           Value
----                           -----
s                              b
e                              c
s                              b
e                              d

Then remove b's items from a:

PS> $a = $a | ? {$b -NotContains $_}

Name                           Value
----                           -----
s                              a
e                              b

Is there a more-succinct way of doing this?

2 Answers 2

3

PS 4.0 using Where method:

$b, $a = $a.Where({$_.s -Eq 'b'}, 'Split')

More info:

Sign up to request clarification or add additional context in comments.

1 Comment

That's pretty slick.
2

I would argue that doing two assignments with a filter and the inverted filter is the most straightforward way of doing this in PowerShell:

$b = $a | ? {$_.s -eq 'b'}       # x == y
$a = $a | ? {$_.s -ne 'b'}       # x != y, i.e. !(x == y)

You could wrap a function around this operation like this (using call by reference):

function Move-Elements {
  Param(
    [Parameter(Mandatory=$true)]
    [ref][array]$Source,
    [Parameter(Mandatory=$true)]
    [AllowEmptyCollection()]
    [ref][array]$Destination,
    [Parameter(Mandatory=$true)]
    [scriptblock]$Filter
  )

  $inverseFilter = [scriptblock]::Create("-not ($Filter)")

  $Destination.Value = $Source.Value | Where-Object $Filter
  $Source.Value      = $Source.Value | Where-Object $inverseFilter
}

$b = @()
Move-Elements ([ref]$a) ([ref]$b) {$_.s -eq 'b'}

or like this (returning a list of arrays):

function Remove-Elements {
  Param(
    [Parameter(Mandatory=$true)]
    [array]$Source,
    [Parameter(Mandatory=$true)]
    [scriptblock]$Filter
  )

  $inverseFilter = [scriptblock]::Create("-not ($Filter)")

  $destination = $Source | Where-Object $Filter
  $Source      = $Source | Where-Object $inverseFilter

  $Source, $destination
}

$a, $b = Remove-Elements $a {$_.s -eq 'b'}

or a combination of the above.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.