Sort an PowerShell array according to a part of content in each element

3.3k views Asked by At

I am working with a powershell script where I have an array containing following data. Each row below is an element in the array.

Each element has two parts seperated by "/" a number (can be 1-12 digits) and a date time.

I need to sort the array according to the date and time given in each element.

201410212339/21-Oct-2014 23:50 -
2251/27-Sep-2014 23:02 -
0436/22-Oct-2014 04:47 -
091342/09-Oct-2014 13:53 -
2220743/22-Oct-2014 07:53 -
20140/22-Sep-2014 07:41 -
2190446/19-Oct-2014 04:56 -
2014258/21-Aug-2014 23:21 -
22110/22-Oct-2014 14:21 -
1410221721/22-Jun-2014 17:33 -
130/23-Jul-2014 11:42 -
10231426/23-Feb-2014 14:38 -
231731/23-Jan-2014 17:43 -
0232039/23-Mar-2014 20:51 -

Can anyone help me with this? I want to sort the array to access the latest or the second latest entry and use the number associated with it. I can try to split each element into number and date-time and sort them but I am looking for a much simpler way.

Thanks in advance.

3

There are 3 answers

2
Jan Chrbolka On BEST ANSWER

If you want to sort by date and time, this is one way of doing it.

This is your data as an array

$data = @("201410212339/21-Oct-2014 23:50 -",
"2251/27-Sep-2014 23:02 -",
"0436/22-Oct-2014 04:47 -",
"091342/09-Oct-2014 13:53 -",
"2220743/22-Oct-2014 07:53 -",
"20140/22-Sep-2014 07:41 -",
"2190446/19-Oct-2014 04:56 -",
"2014258/21-Aug-2014 23:21 -",
"22110/22-Oct-2014 14:21 -",
"1410221721/22-Jun-2014 17:33 -",
"130/23-Jul-2014 11:42 -",
"10231426/23-Feb-2014 14:38 -",
"231731/23-Jan-2014 17:43 -",
"0232039/23-Mar-2014 20:51 -")

Strip extra characters from the end of each line

$data.replace(" -","")

Pre-pend each line by [datetime] representation of date in ticks

$data.replace(" -","") | % { [string]([datetime]::Parse($_.split("/")[1]).ticks) + "@" + $_}

Sort

$data.replace(" -","") | % { [string]([datetime]::Parse($_.split("/")[1]).ticks) + "@" + $_} | sort-object

Remove pre-pended date string and restore the garbage on the end if you want.

$data.replace(" -","") | % { [string]([datetime]::Parse($_.split("/")[1]).ticks) + "@" + $_} | sort-object | %{$_.split("@")[1] + " -"}

Here is the result:

231731/23-Jan-2014 17:43 -
10231426/23-Feb-2014 14:38 -
0232039/23-Mar-2014 20:51 -
1410221721/22-Jun-2014 17:33 -
130/23-Jul-2014 11:42 -
2014258/21-Aug-2014 23:21 -
20140/22-Sep-2014 07:41 -
2251/27-Sep-2014 23:02 -
091342/09-Oct-2014 13:53 -
2190446/19-Oct-2014 04:56 -
201410212339/21-Oct-2014 23:50 -
0436/22-Oct-2014 04:47 -
2220743/22-Oct-2014 07:53 -
22110/22-Oct-2014 14:21 -

EDIT:

My initial attempt at sorting by [datetime] did not work properly

[string]([datetime]::Parse($_.split("/")[1]))

This not suitable for sorting, as it does not sort by year or time. Representing [datetime] in ticks fixes the problem.

[string]([datetime]::Parse($_.split("/")[1]).ticks)

I have edited the code above to reflect this.

1
TheMadTechnician On

You can create properties from each string, sort by the one, and then just re-expand the original... Something like:

@"
201410212339/21-Oct-2014 23:50 -
2251/27-Sep-2014 23:02 -
0436/22-Oct-2014 04:47 -
091342/09-Oct-2014 13:53 -
2220743/22-Oct-2014 07:53 -
20140/22-Sep-2014 07:41 -
2190446/19-Oct-2014 04:56 -
2014258/21-Aug-2014 23:21 -
22110/22-Oct-2014 14:21 -
1410221721/22-Jun-2014 17:33 -
130/23-Jul-2014 11:42 -
10231426/23-Feb-2014 14:38 -
231731/23-Jan-2014 17:43 -
0232039/23-Mar-2014 20:51 -
"@ -split "`r`n"|Select @{l='SortMe';e={[int64]$_.split('/')[0]}},@{l='Value';e={$_}}|sort SortMe|Select -Expand Value

That will output:

130/23-Jul-2014 11:42 -
0436/22-Oct-2014 04:47 -
2251/27-Sep-2014 23:02 -
20140/22-Sep-2014 07:41 -
22110/22-Oct-2014 14:21 -
091342/09-Oct-2014 13:53 -
231731/23-Jan-2014 17:43 -
0232039/23-Mar-2014 20:51 -
2014258/21-Aug-2014 23:21 -
2190446/19-Oct-2014 04:56 -
2220743/22-Oct-2014 07:53 -
10231426/23-Feb-2014 14:38 -
1410221721/22-Jun-2014 17:33 -
201410212339/21-Oct-2014 23:50 -

If you don't want them sorted numerically and want the numbers sorted as string remove the [int64] from it.

0
TessellatingHeckler On

You can pass a code block to sort to make a custom sort property, without rebuilding the array. (Pinching the datetime parse from Jan Chrbolka):

$getDate = { [datetime]::Parse($_.split("/")[1].replace(' -','')) }
$data | sort $getDate

Or sort -Descending to reverse it.

But you aren't going to be able to use the date and number without splitting the line, the search for a "much simpler way" seems a bit fruitless.