I am looking to resort one array based on another array. In a previous project I needed to just get a list of the disordered items, and applying that code to my current scenario I get this
$definedSet = @('C', 'B', 'D', 'A')
$history = @('A', 'B', 'C', 'D')
$disordered = $history.Where({-not [Linq.Enumerable]::SequenceEqual([string[]]$history, [string[]]$definedSet)})
$disordered
Which does indeed give me a list of all four items, because they are all out of order.
However, in this new scenario I need to resort $history
based on $definedSet
. The key being that there could be items in one that aren't in the other. But I am starting with a simpler problem, and that has me stumped. I feel certain [Linq.Enumerable]
is the key, obviously, but my Google-Fu is not pointing me towards a solution. I have tried the Microsoft Docs article on the Enumerable class, and my brain... melted.
In this case you can sort by index, using Array.IndexOf:
OverloadDefinitions
-------------------
int IList.IndexOf(System.Object value)
However it's worth noting this method is case-sensitive. If you wish to find indexes with a case-insensitive method you can use Array.FindIndex:
OverloadDefinitions
-------------------
static int FindIndex[T](T[] array, System.Predicate[T] match)
static int FindIndex[T](T[] array, int startIndex, System.Predicate[T] match)
static int FindIndex[T](T[] array, int startIndex, int count, System.Predicate[T] match)
Or you can initialize the set as a List<T>
and use it's FindIndex(Predicate<T>)
method.
Both options should use a case-insensitive equality comparer (-eq
/ -ne
) in their Predicate<T>
.
Sort-Object
allows you to sort by multiple expressions, in the example below it will sort first by the found index in the set and then alphabetically:
$definedSet = 'powershell', 'is', 'awesome'
$history = 'Awesome', 'PowerShell', 'set', 'not in', 'is'
$predicate = [Predicate[string]] { $args[0] -eq $_ }
$history | Sort-Object { [array]::FindIndex($definedSet, $predicate) }, { $_ }