9

I need to convert a HashSet to an ArrayList?

$hashset = New-Object System.Collections.Generic.HashSet[int]
$hashset.Add(1)
$hashset.Add(2)
$hashset.Add(3)

$arraylist = New-Object System.Collections.ArrayList
# Now what?
marsze
  • 15,079
  • 5
  • 45
  • 61
Daniel
  • 3,092
  • 3
  • 32
  • 49
  • did you try [array]$arraylist = $hashset . both variables after this still pipe to "get-member" with the same output. What is your goal in creating an array vs a "hashset" – Robert Cotterman Oct 24 '18 at 06:29
  • @RobertCotterman I need an ArrayList. Arrays are fixed size and don't have `Sort()`. – Daniel Oct 24 '18 at 06:35
  • 1
    Daniel, arrays in Powershell can be sorted with Sort-Object and you can add items to them (it will create a new array to do that, but from a language standpoint it doesn't really matter what the type is -- unless, of course, you totally ed the ArrayList to pass to a method that requires one. But I hope such APIs are long dead now.) – Joey Oct 24 '18 at 07:50
  • @Joey I often prefer using ArrayList or List because the way PowerShell handles arrays, especially when adding new items, is *damn slow*. – marsze Oct 24 '18 at 07:53
  • @Joey The lists can become quite big and I don't want to copy big lists every time I add one item. Beside that, I also need `GetRange()` which also isn't supported by the Array that `Sort-Object` returns. – Daniel Oct 24 '18 at 08:02
  • @marze: Indeed, with the added details using a list is preferable. I just tend to write PowerShell in a way that minimises mutation of collections and instead use the pipeline for such things as much as possible. It's not always possible or convenient, of course. – Joey Oct 24 '18 at 08:46

3 Answers3

7

One way, using CopyTo:

$array = New-Object int[] $hashset.Count
$hashset.CopyTo($array)
$arraylist = [System.Collections.ArrayList]$array

Another way (shorter, but slower for large hashsets):

$arraylist = [System.Collections.ArrayList]@($hashset)

Also, I strongly recommend to favor List over ArrayList, as it's pretty much deprecated since the introduction of generics:

$list = [System.Collections.Generic.List[int]]$hashset
marsze
  • 15,079
  • 5
  • 45
  • 61
  • Didn't know about lists. Thanks. – Daniel Oct 24 '18 at 08:11
  • 1
    Nice, List[int]++. Worth noting that if you're using PowerShell >5.0, the constructor takes any `IEnumerable[int]` (including `HashSet[int]`) directly as its argument, faster than casting it: `[System.Collections.Generic.List[int]]::new($hashset)` – Mathias R. Jessen Oct 24 '18 at 09:33
  • @MathiasR.Jessen Did you actually try if it's faster? Because PowerShell's cast does use a constructor implicitly, if possible. – marsze Oct 24 '18 at 10:38
  • https://blogs.msdn.microsoft.com/powershell/2013/06/11/understanding-powershells-type-conversion-magic/ – marsze Oct 24 '18 at 10:44
  • @marsze yes, but due to `@()`, the set is expanded to an array first. If I pass it directly to the constructor, I have it return the new list in approx. 10ms, whereas if I do your cast, it gets slower the bigger the set gets :) – Mathias R. Jessen Oct 24 '18 at 11:40
  • 1
    @MathiasR.Jessen I've already removed the `@()` in my answer, it's unnecessary, as you correctly stated. *Another* nice benefit of using `List` instead of `ArrayList`! Then you can just do the cast and it will be about the same speed is it's (most likely) using the constructor internally. – marsze Oct 24 '18 at 11:47
  • @marsze sorry, didn't see you'd updated the answer, looking sweet :-D – Mathias R. Jessen Oct 24 '18 at 11:50
4

Unsure if this is what you are after but it here you go...

$hashset = New-Object System.Collections.Generic.HashSet[int]
$null = $hashset.Add(1)
$null = $hashset.Add(2)
$null = $hashset.Add(3)
# @($hashset) converts the hashset to an array which is then 
# converted to an arraylist and assigned to a variable
$ArrayList = [System.Collections.ArrayList]@($hashset)
Drew
  • 3,814
  • 2
  • 9
  • 28
1

You can also add every item from hashtable to array using foreach loop:

$hashset = New-Object System.Collections.Generic.HashSet[int]
$hashset.Add(1)
$hashset.Add(2)
$hashset.Add(3)

$arraylist = New-Object System.Collections.ArrayList
# Now what?
foreach ($item in $hashset){
    $arraylist.Add($item)
}
Kirill Pashkov
  • 3,118
  • 1
  • 15
  • 20
  • 2
    You should use `$arraylist.Add($item) | Out-Null` or `[void]$arraylist.Add($item)` to prevent unwanted output to the pipeline. – marsze Oct 24 '18 at 07:48
  • Thanks. That's how I do it at the moment. But it's unnecessarily verbose for my taste. – Daniel Oct 24 '18 at 08:04