<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>PowerShell</title>
        <link>http://www.nimblecoder.com/blog/category/24.aspx</link>
        <description>PowerShell</description>
        <language>en-US</language>
        <copyright>Ryan Van Slooten</copyright>
        <generator>Subtext Version 2.1.1.1</generator>
        <item>
            <title>Using PowerShell to Select a Unique Array</title>
            <link>http://nimblecoder.com/blog/archive/2011/12/09/using-powershell-to-select-a-unique-array.aspx</link>
            <description>&lt;p&gt;I had an XML file with names that I needed to verify in a database table, so I thought this would be a perfect task for PowerShell. The actual format of the XML file looked like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;symbol:U_F80_T410.ADDITIONS&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;ADDITIONS&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;click&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;True&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;click&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;en&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;True&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;en&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Obtaining the XML nodes was simple with PowerShell. I need to find the symbol name, so I selected the &amp;lt;menu&amp;gt; nodes that had &amp;lt;id&amp;gt; nodes starting with 'symbol:' and extracted the name with Substring():&lt;/p&gt;

&lt;pre class="csharpcode"&gt;$menuSymbols = $xml.SelectNodes(&lt;span class="str"&gt;"//menu[contains(id, 'symbol:')]"&lt;/span&gt;) | % { $_.id.Substring(7) }&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;Next I need the tag name of each symbol (U_F80_T410 in the sample above). Some symbols don’t have tag names, and tag names can have multiple symbol names, e.g. U_F80_T410.ADDITIONS and U_F80_T410.OVERVIEW.&lt;/p&gt;

&lt;p&gt;Method 1: Declare array first, then use the | % ForEach-Object alias&lt;/p&gt;

&lt;pre class="csharpcode"&gt;$menuTagNames = @() 
$menuSymbols | % { 
    $index = $_.IndexOf(&lt;span class="str"&gt;'.'&lt;/span&gt;) 
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ($index &lt;span class="preproc"&gt;-gt&lt;/span&gt; 0) { 
        $tagName = $_.Substring(0, $index) 
        &lt;span class="kwrd"&gt;if&lt;/span&gt; ($menuTagNames -notcontains $tagName) { 
            $menuTagNames += $tagName 
        } 
    } 
} &lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;I thought there must be a more concise means to get the unique symbol names. A quick look at stackoverflow showed 'select -uniq' and 'sort -uniq' as methods to &lt;a href="http://stackoverflow.com/questions/1391853/removing-duplicate-values-from-a-powershell-array"&gt;remove duplicates in PowerShell&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Method 2: Using Sort -Unique&lt;/p&gt;

&lt;pre class="csharpcode"&gt;$menuTagNames = $menuSymbols | % {
  $index = $_.IndexOf(&lt;span class="str"&gt;'.'&lt;/span&gt;)
  &lt;span class="kwrd"&gt;if&lt;/span&gt; ($index &lt;span class="preproc"&gt;-gt&lt;/span&gt; 0) { $_.Substring(0, $index) }
} | Sort -Unique &lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;It should be noted that Method 2 does not always return an array, but instead it depends how many items are returned from the pipeline. If no items are returned, the result will be $null. If one item is returned, the result will be a string since the underlying data type is string. If two or more items are returned, the result will be an array.&lt;/p&gt;

&lt;p&gt;One other point to mention is that the underlying .NET data type for the PowerShell [array] is System.Array which is not optimized for large results or for searching for items in the list. I haven’t tested the performance aspects in this scenario, but the [hashtable] should theoretically be more efficient however it requires more memory and more code. I started to convert Method 2 into a hashtable:&lt;/p&gt;

&lt;p&gt;Method 3: Method 2 using a hashtable&lt;/p&gt;

&lt;pre class="csharpcode"&gt;$menuTagNames = @{}
$menuTagNames = $menuSymbols | % {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ($_.IndexOf(&lt;span class="str"&gt;'.'&lt;/span&gt;) &lt;span class="preproc"&gt;-gt&lt;/span&gt; 0) {
        $_.Substring(0, $_.IndexOf(&lt;span class="str"&gt;'.'&lt;/span&gt;))
    }
} | Sort -Uniq | % $h.Add($_, $_)&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;I like Method 3, however it could be optimized further because the items in the 'if' conditional could be tested for duplicates immediately using the hashtable ContainsKey() method:&lt;/p&gt;

&lt;p&gt;Method 4: Back to Method 1 except with a hashtable&lt;/p&gt;

&lt;pre class="csharpcode"&gt;$menuTagNames = @{} 
$menuSymbols | % { 
    $index = $_.IndexOf(&lt;span class="str"&gt;'.'&lt;/span&gt;) 
    &lt;span class="kwrd"&gt;if&lt;/span&gt; ($index &lt;span class="preproc"&gt;-gt&lt;/span&gt; 0) { 
        $tagName = $_.Substring(0, $index) 
        &lt;span class="kwrd"&gt;if&lt;/span&gt; ( !$menuTagNames.ContainsKey($tagName) ) { 
            $menuTagNames.Add($tagName, $tagName) 
        } 
    } 
} &lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;The more I play with PowerShell, the more I like it.&lt;/p&gt;&lt;img src="http://nimblecoder.com/blog/aggbug/81.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ryan Van Slooten</dc:creator>
            <guid>http://nimblecoder.com/blog/archive/2011/12/09/using-powershell-to-select-a-unique-array.aspx</guid>
            <pubDate>Fri, 09 Dec 2011 21:08:31 GMT</pubDate>
            <wfw:comment>http://nimblecoder.com/blog/comments/81.aspx</wfw:comment>
            <comments>http://nimblecoder.com/blog/archive/2011/12/09/using-powershell-to-select-a-unique-array.aspx#feedback</comments>
            <wfw:commentRss>http://nimblecoder.com/blog/comments/commentRss/81.aspx</wfw:commentRss>
            <trackback:ping>http://nimblecoder.com/blog/services/trackbacks/81.aspx</trackback:ping>
        </item>
    </channel>
</rss>
