How to initialize an array of custom objects

后端 未结 9 2439
粉色の甜心
粉色の甜心 2020-12-13 23:44

First, as this leads to my question, I\'ll start by noting that I\'ve worked with XML a fair bit in PowerShell, and like how I can read data from XML files, quickly, into ar

相关标签:
9条回答
  • 2020-12-14 00:20

    I'd do something along these lines:

    $myitems =
    @([pscustomobject]@{name="Joe";age=32;info="something about him"},
    [pscustomobject]@{name="Sue";age=29;info="something about her"},
    [pscustomobject]@{name="Cat";age=12;info="something else"})
    

    Note that this only works in PowerShell 3, but since you did not mention the version in your question I'm assuming this does not matter for you.

    Update

    It has been mentioned in comments that if you do the following:

    $younger = $myitems | Where-Object { $_.age -lt 20 } 
    Write-Host "people younger than 20: $($younger.Length)" 
    

    You won't get 1 as you might expect. This happens when a single pscustomobject is returned. Now this is not a problem for most of other objects in PowerShell, because they have surrogate properties for Length and Count. Unfortunately pscustomobject does not. This is fixed in PowerShell 6.1.0. You can work around this by using operator @():

    $younger = @($myitems | Where-Object { $_.age -lt 20 })
    

    For more background see here and here.

    Update 2

    In PowerShell 5 one can use Classes to acheive similar functionality. For example you can define a class like this:

    class Person {
        [string]$name
        [int]$age
        [string]$info; `
    `
        Person(
        [string]$name,
        [int]$age,
        [string]$info
        ){
            $this.name = $name
            $this.age = $age
            $this.info = $info
        }
    }
    

    Backticks here are so that you could copy and paste it to the command line, they are not required in a script. Once the class is defined you can the create an array the usual way:

    $myitems =@([Person]::new("Joe",32,"something about him"),
    [Person]::new("Sue",29,"something about her"),
    [Person]::new("Cat",12,"something else"))
    

    Note that this way does not have the drawback mentioned in the previous update, even in PowerShell 5.

    Update 3

    You can also intialize a class object with a hashtable, similar to the first example. For that you need to make sure that a default contructor defined. If you do not provide any constructors, one will be created for you, but if you provide a non-default one, default constructor won't be there and you will need to define it explicitly. Here is an example with default constructor that is auto-created:

    class Person {
        [string]$name
        [int]$age
        [string]$info;
    }
    

    With that you can:

    $person = @([Person]@{name='Kevin';age=36;info="something about him"}
    [Person]@{name='Sue';age=29;info="something about her"}
    [Person]@{name='Cat';age=12;info="something else"})
    

    This is a bit more verbose, but also a bit more explicit. Thanks to @js2010 for pointing this out.

    0 讨论(0)
  • 2020-12-14 00:22

    Maybe you mean like this? I like to make an object and use Format-Table:

    > $array = @()
    > $object = New-Object -TypeName PSObject
    > $object | Add-Member -Name 'Name' -MemberType Noteproperty -Value 'Joe'
    > $object | Add-Member -Name 'Age' -MemberType Noteproperty -Value 32
    > $object | Add-Member -Name 'Info' -MemberType Noteproperty -Value 'something about him'
    > $array += $object
    > $array | Format-Table
    
    Name                                                                        Age Info
    ----                                                                        --- ----
    Joe                                                                          32  something about him
    

    This will put all objects you have in the array in columns according to their properties.

    Tip: Using -auto sizes the table better

    > $array | Format-Table -Auto
    
    Name Age Info
    ---- --- ----
    Joe   32 something about him
    

    You can also specify which properties you want in the table. Just separate each property name with a comma:

    > $array | Format-Table Name, Age -Auto
    
    Name Age
    ---- ---
    Joe   32
    
    0 讨论(0)
  • 2020-12-14 00:24

    Given the data above, this is how I would do it:

    # initialize the array
    [PsObject[]]$people = @()
    
    # populate the array with each object
    $people += [PsObject]@{ Name = "Joe"; Age = 32; Info = "something about him" }
    $people += [PsObject]@{ Name = "Sue"; Age = 29; Info = "something about her" }
    $people += [PsObject]@{ Name = "Cat"; Age = 12; Info = "something else" }
    

    The below code will work even if you only have 1 item after a Where-Object:

    # display all people
    Write-Host "People:"
    foreach($person in $people) {
        Write-Host "  - Name: '$($person.Name)', Age: $($person.Age), Info: '$($person.Info)'"
    }
    
    # display with just 1 person (length will be empty if using 'PSCustomObject', so you have to wrap any results in a '@()' as described by Andrew Savinykh in his updated answer)
    $youngerPeople = $people | Where-Object { $_.Age -lt 20 }
    Write-Host "People younger than 20: $($youngerPeople.Length)"
    foreach($youngerPerson in $youngerPeople) {
        Write-Host "  - Name: '$($youngerPerson.Name)'"
    }
    

    Result:

    People:
      - Name: 'Joe', Age: 32, Info: 'something about him'
      - Name: 'Sue', Age: 29, Info: 'something about her'
      - Name: 'Cat', Age: 12, Info: 'something else'
    People younger than 20: 1
      - Name: 'Cat'
    
    0 讨论(0)
  • 2020-12-14 00:29

    Here is a more concise version of the accepted answer which avoids repeating the NoteProperty identifiers and the [pscustomobject]-cast:

    $myItems =  ("Joe",32,"something about him"), ("Sue",29,"something about her")
                | ForEach-Object {[pscustomobject]@{name = $_[0]; age = $_[1]; info = $_[2]}}
    

    Result:

    > $myItems
    
    name           age         info
    ----           ---         ----
    Joe            32          something about him
    Sue            29          something about her
    
    0 讨论(0)
  • 2020-12-14 00:30

    The simplest way to initialize an array

    Create array

    $array = @()
    

    Create your header

    $line = "" | select name,age,phone
    

    Fill the line

    $line.name = "Leandro"
    $line.age = "39"
    $line.phone = "555-555555"
    

    Add line to $array

    $array += $line
    

    Result

    $array
    
    name                                                     age                                                      phone
    ----                                                     ---                                                      -----
    Leandro                                                  39                                                       555-555555
    
    0 讨论(0)
  • 2020-12-14 00:30

    A little variation on classes. Initialize it with hashtables.

    class Point { $x; $y }
    
    $a = [Point[]] (@{ x=1; y=2 },@{ x=3; y=4 })
    
    $a
    
    x y        
    - -          
    1 2
    3 4
    
    $a.gettype()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Point[]                                  System.Array
    
    $a[0].gettype()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     False    Point                                    System.Object
    
    0 讨论(0)
提交回复
热议问题