问题
I'm essentially trying to create a list of pairs which is proving frustratingly difficult
Note before anyone mentions Hashtables that there will be duplicates which I don't care about.
For example, if I do
$b = @{"dog" = "cat"}
I get
Name Value ---- ----- dog cat
which is good. However, I'm then unable to add the likes of
$b += @{"dog" = "horse"}
Item has already been added. Key in dictionary: 'dog' Key being added: 'dog'
I'm just trying to create a table of data which I can add to using something like .Add() or +=.
回答1:
Persistent13's helpful answer offers an effective and efficient solution - albeit a slightly obscure one.
Creating an array of hashtables is the simplest solution, though it's important to note that "extending" an array means implicitly recreating it, given that arrays are fixed-size data structures, which can become a performance problem with many iterations:
# Using array-construction operator ",", create a single-element array
# containing a hashtable
$b = , @{ dog = "cat"}
# "Extend" array $b by appending another hashtable.
# Technically, a new array must be allocated that contains the original array's
# elements plus the newly added one.
$b += @{ dog = "horse"}
This GitHub issue discusses a potential future enhancement to make PowerShell natively support an efficiently extensible list-like data type or for it to even default to such a data type. (As of Windows PowerShell v5.1 / PowerShell Core 6.2.0, PowerShell defaults to fixed-size arrays, of type [object[]]).
回答2:
I believe a list of hashtables should accomplish what you are after.
$ht = @{foo='bar'}
$list = [System.Collections.Generic.List[hashtable]]::new()
$list.Add($ht)
$list.Add($ht)
$list.Add($ht)
$list
回答3:
If you want a list of tuples I'd recommend actually building a list of tuples:
$list = @()
$tuple1 = New-Object 'Tuple[String,String]' 'dog', 'cat'
$tuple2 = New-Object 'Tuple[String,String]' 'dog', 'horse'
$list += $tuple1
$list
# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog cat 2
$list += $tuple2
$list
# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog cat 2
# dog horse 2
Note that in this example $list is a regular array, meaning that, as @mklement0 pointed out in his answer, appending to it with the += assignment operator will re-create the array with size increased by 1, put the new item in the new empty slot, then replace the original array. For a small number of append operations this usually isn't a big issue, but with increasing number of append operations the performance impact becomes significant.
Using an ArrayList instead of a plain array avoids this issue:
$list = New-Object Collections.ArrayList
$tuple1 = New-Object 'Tuple[String,String]' 'dog', 'cat'
$tuple2 = New-Object 'Tuple[String,String]' 'dog', 'horse'
$list.Add($tuple1) | Out-Null
$list
# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog cat 2
$list.Add($tuple2) | Out-Null
$list
# Output:
#
# Item1 Item2 Length
# ----- ----- ------
# dog cat 2
# dog horse 2
The Add() method of ArrayList objects outputs the index where the item was appended. Out-Null suppresses that output that is in most cases undesired. If you want to work with these index numbers you can collect them in a variable instead of discarding them ($i = $list.Add($t1)).
If you want to avoid having to specify the type of a new tuple all the time you can wrap it into a reusable function like this:
function New-Tuple {
Param(
[Parameter(Mandatory=$true)]
[ValidateCount(2,2)]
[string[]]$Values
)
New-Object 'Tuple[String,String]' $Values
}
$tuple1 = New-Tuple 'dog', 'cat'
$tuple2 = New-Tuple 'dog', 'horse'
or, in a more generic way, like this:
function New-Tuple {
Param(
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[ValidateCount(2,20)]
[array]$Values
)
Process {
$types = ($Values | ForEach-Object { $_.GetType().Name }) -join ','
New-Object "Tuple[$types]" $Values
}
}
$tuples = ('dog', 'cat'), ('dog', 'horse') | New-Tuple
回答4:
Thanks to mklement0 as below is probably the simplest solution
$b = , @{ dog = "cat"}
$b += @{ dog = "horse"}
And Persistent13's method also yields an easy route
$ht = @{foo='bar'}
$list = [System.Collections.Generic.List[hashtable]]::new()
$list.Add($ht)
$list.Add($ht)
$list.Add($ht)
$list
I suppose i was just surprised that there wasn't a more ingrained way to get what i feel is a pretty basic/standard object type
来源:https://stackoverflow.com/questions/54373785/tuples-arraylist-of-pairs