Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query a list LINQ-style in PowerShell

add-type -Language CSharpVersion3 -TypeDefinition @"
    public class pack_code
    {
        public pack_code() {}

        public string code { get; set; }
        public string type { get; set; }
    }
"@

$a = New-Object pack_code
$a.code = "3"
$a.type = "5"
$b = New-Object pack_code
$b.code = "2"
$b.type = "5"
$c = New-Object pack_code
$c.code = "2"
$c.type = "5"
$d = New-Object pack_code
$d.code = "1"
$d.type = "1"

$codes = New-Object 'System.Collections.Generic.List[object]'
$codes.add($a)
$codes.add($b)
$codes.add($c)
$codes.add($d)

Is there a way to select distinct from $codes and select the objects where type equals 1? How can I use LINQ with PowerShell?

like image 359
Varyanica Avatar asked May 19 '10 22:05

Varyanica


2 Answers

What Keith said. Plus, changed the constructor in your C# and used the -Unique parameter on the Sort cmdlet.

Add-Type -Language CSharpVersion3 -TypeDefinition @"
    public class pack_code
    {
        public pack_code(string code, string type) {
            this.code=code;
            this.type=type;
        }

        public string code { get; set; }
        public string type { get; set; }
    }
"@

$codes = New-Object 'System.Collections.Generic.List[object]'
$codes.Add( ( New-Object pack_code 3, 5 ))
$codes.Add( ( New-Object pack_code 2, 5 ))
$codes.Add( ( New-Object pack_code 2, 5 ))
$codes.Add( ( New-Object pack_code 1, 1 ))
$codes.Add( ( New-Object pack_code 2, 2 ))
$codes.Add( ( New-Object pack_code 2, 1 ))
$codes.Add( ( New-Object pack_code 2, 1 ))

$codes | sort code, type -Unique | where {$_.type -eq 1}
like image 180
Doug Finke Avatar answered Oct 13 '22 07:10

Doug Finke


Doug Finke's helpful answer and Keith Hill's helpful answer show you PowerShell-idiomatic analogs to the .Distinct() and .Where() LINQ methods.


In PowerShell v3 or higher you now can use LINQ.

The solution below demonstrates that LINQ can be used to solve your problem, but also shows that doing so is requires somewhat cumbersome syntax and is probably only worth the effort if you need advanced query features and/or performance matters.

  • See this answer for a general overview of how to use LINQ from PowerShell.

# Create the type whose instances will make up the list to filter.
# Make it implement IEquatable<T> with custom comparison logic that
# compares property values so that the .Distinct() LINQ method works correctly.
Add-Type -TypeDefinition @"

  public class pack_code : System.IEquatable<pack_code>
  {
      public string code { get; set; }
      public string type { get; set; }

      // IEquatable<T> interface implementation

      // Test equality of this object with another of the same type.
      public bool Equals(pack_code other) {
        // Note: Normally, you'd need to deal with the case of other == null as well.
        return this.code == other.code && this.type == other.type;
      }

      // If Equals() returns true for a pair of objects  
      // then GetHashCode() must return the same value for these objects.         
      public override int GetHashCode() {
        return this.code.Length + this.type.Length;
      }
  }

"@

# Create the list to filter.
# Note:
#  * Despite not having a constructor for [pack_code], PowerShell is smart
#    enough to construct an instance from a cast from a hashtable that contains
#    entries whose names match the settable [pack_code] properties.
#  * The array of [pack_code] instances is then cast to the list type.
#  * The list contains 3 objects of type 1, but only 2 distinct ones.
$codes = [System.Collections.Generic.List[pack_code]] (
           [pack_code] @{code = '2'; type = '1'},
           [pack_code] @{code = '3'; type = '5'},
           [pack_code] @{code = '2'; type = '1'},
           [pack_code] @{code = '1'; type = '1'}
         )

# Invoke the LINQ methods as static methods of the 
# [System.Linq.Enumerable] type to
# return all distinct objects whose type property is ‘1’.
# Note that the result will be an *iterator*; if you want a
# static array, wrap the call in [Linq.Enumerable]::ToArray(...)
[Linq.Enumerable]::Where(
  [Linq.Enumerable]::Distinct($codes),
  [Func[pack_code, bool]] { $Args[0].type -eq '1' }
)
like image 45
mklement0 Avatar answered Oct 13 '22 07:10

mklement0