现在的位置: 首页 > 综合 > 正文

PowerShell Sort Array

2013年10月05日 ⁄ 综合 ⁄ 共 6950字 ⁄ 字号 评论关闭

Note: This is part two of a multiple blog series about working with arrays and hash tables for data storage. In yesterday’s Hey, Scripting Guy! Blog,

Learn Simple Ways to Handle Windows PowerShell Arrays
, I discussed creating arrays, indexing into arrays, and two techniques for walking through an array.

Working with specific array elements

One of the interesting things about arrays in Windows PowerShell is they are able to hold different data types. For example, I can store numbers and strings in the same array as shown here.

PS C:\> $a = 1,2,3,"four"

PS C:\> $a

1

2

3

Four

Changing element values

If I need to change an element in array, I can index into the array by using the square bracket and the index number. To find the upper boundary, I use the
GetUpperBound method, and when I have that value, I can easily find the element I need to modify. This technique is shown here.

PS C:\> $a.GetUpperBound(0)

3

PS C:\> $a[3] = 4

PS C:\> $a

1

2

3

4

Adding a new element to an existing array

If I want to add an element to an existing array, it might make sense to choose the next index number, and attempt to assign a value in the same way that I change an existing value. When I do this, however, Windows PowerShell generates an out of range error
message. This command and error message are shown here.

PS C:\> $a[4] = 12

Array assignment failed because index '4' was out of range.

At line:1 char:4

+ $a[ <<<< 4] = 12

    + CategoryInfo          : InvalidOperation: (4:Int32) [], RuntimeException

    + FullyQualifiedErrorId : IndexOutOfRange

The way to add a new element to an existing array is to use the += operator as shown here.

$a += 12

The commands to create an array, get the upper boundary of an array, change an element in an array, and add a new element to an array are shown here with their associated output.

Image of script

Searching for a specific value in an array

One question that comes up from time-to-time is, “How do I know whether a value is contained in an array?” The answer is, once again, rather easy, “Use the
Contains operator”. The following two commands use the previously created
$a array. In the first command, the number 12 is present, and the value
True returns. In the second example, the array does not contain the number 14; and therefore, the returned value is
False.

PS C:\> $a -contains 12

True

PS C:\> $a -contains 14

False

PS C:\>

Sorting an array

Now suppose I need to sort my array. There are actually two ways to do this. The first way to do this is to use the
Sort-Object cmdlet (Sort is an alias for the
Sort-Object
cmdlet). The second way to sort an array is to use the static
Sort method from the System.Array .NET Framework class.

Use Sort and the pipeline

The first technique I will discuss is also the easiest to use. It is the pipeline method. All that this technique requires is to pipe the array to the cmdlet. This technique is shown here.

PS C:\> [int[]]$a = 1,5,7,2,12,4

PS C:\> $a | Sort-Object

1

2

4

5

7

12

The thing to keep in mind is that this does not change the array, it merely changes the display output. If I want to modify the actual array, I need to write the results back to the original array. This technique is shown here.

PS C:\> $a = $a | sort

PS C:\> $a

1

2

4

5

7

12

The commands to create an array of integers, sort the results with the
Sort-Object
cmdlet, and write the results back to the array are shown in the following image.

Image of script

Use Get-Random to create a random array

One of my favorite tricks is to create an array of numbers by using the
Get-Random
cmdlet. To do this, I use Count to specify the number of values to select, and I use a range operator to create an array of numbers from which to choose. I then write the random values to a variable. This technique
is shown here.

$rnd = Get-Random -Count 10 -InputObject (1..100000)

Use the static Sort method

To sort the random numbers, I use the Sort static method from the
System.Array .NET Framework class. Because Sort
is a static method, I need to use a double colon separator between the class name (in square brackets) and the method name. I supply the array of random numbers as an input value. This command is shown here.

[array]::sort($rnd)

What is really interesting is that the Sort static method, automatically writes the sorted values back to the array that is contained in the
$rnd variable. The commands to create a random array of numbers, display those values, sort the array, and display the sorted list are shown in the following image.

Image of script

Measuring the difference in performance

“So, what is the difference between the two ways to sort arrays,” you may ask. The difference is that the pipeline way of sorting is probably more intuitive to Windows PowerShell users. The other difference is that the static
Sort method from the System.Array class is way faster. To check this, I like to use the
Measure-Command cmdlet. To ensure I have a large enough data set that will take a decent amount of time to sort, I create two random arrays by using the commands that are shown here.

$arrayA = Get-Random -Count 1000000 -InputObject (1..1000000)

$arrayB = Get-Random -Count 1000000 -InputObject (1..1000000)

Next, I use the Measure-Command cmdlet to measure the two ways of sorting arrays. The two commands are shown here.

Measure-Command -Expression { $arrayA = $arrayA | Sort-Object }

Measure-Command -Expression { [array]::Sort($arrayB) }

On my system (which is a fast computer), the first command takes a little over 40 seconds, whereas the second command takes a little more than 8 seconds. Therefore, the second command appears to be five times faster than the first command that uses the pipeline.

The commands that create the two random arrays use Measure-Command
to check the speed of the two commands, and they display the first two numbers in each of the newly sorted arrays, as shown in the following image.

Image of script

Sorting arrays that contain multiple types

There is one more caveat when it comes to using the two sort methods. Because an array in Windows PowerShell can contain different types, the
Sort-Object method may be the preferred way of sorting objects. This is because in using the default comparer, the
Sort static method fails when the array contains different types.

In the following example, I create an array that contains both integers and strings. I then pipe the array to the
Sort-Object cmdlet (using Sort as the alias). Next, I attempt to use the static
Sort method from the System.Array class, and that generates an error message.

PS C:\> $array = 1,2,9,8,3,"four","tree","Cat","bat"

PS C:\> $array | sort

1

2

3

8

9

bat

Cat

four

tree

PS C:\> [array]::sort($array)

Exception calling "Sort" with "1" argument(s): "Failed to compare two elements in the array."

At line:1 char:14

+ [array]::sort <<<< ($array)

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : DotNetMethodException

PS C:\>

Because an array can contain other objects (besides strings and integers), I decide to perform one additional test, and I therefore store an instance of the
System.Diagnostics.Process .NET Framework class in the last element. This command is shown here.

PS C:\> $array = 1,2,9,8,3,"four","tree","Cat","bat",(get-process winword)

PS C:\> $array

1

2

9

8

3

four

tree

Cat

bat

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

    463      62    41772      89736   369    39.17   4460 WINWORD

Next, I decide to sort the array. Once again, the Sort-Object cmdlet comes through with no problems. This output is shown here.

PS C:\> $array | sort

1

2

3

8

9

bat

Cat

four

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

    463      62    41772      89736   369    39.17   4460 WINWORD

tree

PS C:\>

PT, that is all there is to modifying values in an array, adding to an array, checking to see if an array contains a specific value, and sorting the array. Array Week will continue tomorrow when I will store different types of objects in an array (including
other arrays). It will be fun and educational. See ya!

I invite you to follow me on
Twitter
and Facebook. If you have any questions, send email to me at
scripter@microsoft.com, or post your questions on the
Official Scripting Guys Forum. See you tomorrow. Until then, peace.

抱歉!评论已关闭.