Home > Software design >  Resort one array based on another array
Resort one array based on another array

Time:06-19

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.

CodePudding user response:

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:

[Collections.Generic.List[string]] $definedSet = @(
    'powershell', 'is', 'awesome'
)
$history   = 'Awesome', 'PowerShell', 'set', 'not in', 'is'
$predicate = [Predicate[string]]{ param($i) $i -eq $_ }

$history | Sort-Object { $definedSet.FindIndex($predicate) }, { $_ }
  • Related