Is this a "Powershell Way" of counting?

This topic contains 6 replies, has 3 voices, and was last updated by  Ramon Tan 1 month ago.

  • Author
    Posts
  • #102605

    Ramon Tan
    Participant

    I wrote the ff. script to count the number of records (i.e., lines) in a very simple CSV file:
    $nrec = 0;
    Import-Csv .\INPUTFILE.csv -Delimiter / | Select Prop1,Prop2 | Where Prop1 -NE "" |
    Foreach {$_; $nrec = $nrec + 1} | Out-Null
    $nrec

    The condition: (Prop1 -NE "") is the criteria for sensing that there are no more non-empty records because Property Prop1 = "".
    This is because the file as originally created wrote blanks after the last "real data" record in order to fit the same number of records all the time. (Why? I don't know, except to say it was a legacy system, or practice!)
    With that said, I am curious if this is the "Powershell way" (or the "right way") even if it works for my specific needs. It seems inefficient to run through every record just to get a cound, but as a PS beginner, I'd like not to use PS for what it wasn't intended to do, even if "it works".
    Any comments, hints or advice would be appreciated.

  • #102607

    L-Bo
    Participant

    If all you desire is a count of the records in the CSV I have a couple of suggestions.

    Import-Csv -Path Path\To\Somefile.csv | Measure-Object | select count
    

    A shorter way is to use the .Count method as seen below

    (Import-Csv -Path Path\To\Somefile.csv).count
    

    Hope this helps!

    • #102616

      Ramon Tan
      Participant

      Yes, Mr L-Bo, it works beautifully ... and thanks to you for your generous help.
      As a follow-up, I ran the same command but without the .Count and piped it to get-member:

      (Import-Csv -Path Path\To\Somefile.csv) | Get-Member

      and got a listing of methods and properties — something I learned early on from the book of Jones & Hicka, which has proven to be extremely useful. But to my surprise, the listing did NOT include 'Count' as a method. I was expecting it.

      I must be missing something. I am asking this because so far, I've found the Get-member cmdlet, as advised in that book, to be a very useful source of discovering what can and cannot be done with the "data in the pipeline" as a script progresses through a series of commands.

      Would be grateful for any advice, tips or hints.

  • #102613

    James Crompton
    Participant

    Since you want to filter out some records before reading the count you can do just that

    $values = Import-Csv .\INPUTFILE.csv -Delimiter / | Where Prop1 -NE ""  #filter records so only valid ones are captures in $values
    $values.Count #< -- gives the number of records from the csv which had a valid Prop1
    
    • #102617

      Ramon Tan
      Participant

      Hello Mr Crompton,

      I am extremely grateful for your creative suggestion/solution.
      I tried it and it works perfectly.
      To follow-up for my own education, I executed your script one step further, which is to run:

      > $values | Get-Member

      and was rather surprised that Count did not appear as a method. I am definitely missing some "principle of PS operation".
      I was of the understanding that piping any object or collection from a command to Get-Member would yield a list of methods, properties, etc. that are relevant to that object. Naturally, I think there must be a "common" or "universal" set of methods that exist for each item (variable, cmdlet, object, etc.) in Powershell as long as the context is semantically valid, mcuh like the 9 to all cmdlets.

      Any hints or advice would be highly appreciated.
      Sincerely,

  • #102619

    James Crompton
    Participant

    I can understand how get-member may have confused you here because PowerShell does a number of "helpful" things when dealing with piped collections and arrays. The get-member call is actually behaving on the items in the collection and not the collection itself due to the piping. PowerShell does a number of things to help you work with collections easier but it can also be confusing when it does something you don't expect.

    If you want the members from the collection itself and not the members on the items inside don't pipe the object but do.

    Get-Member -InputObject $values
    

    There are other shorthands PowerShell allows for instance when you have a collection you can actually reference child properties of the entire collection and get a new collection.

    For example

    $values.Prop1

    In most languages this would fail because $values in an object array and Prop1 is on each element of the object and not on the collection but in PowerShell this will return a collection with all the Prop1 values from each element.

    • #102629

      Ramon Tan
      Participant

      Thank you again, Mr Crompton. I "played" with the commands you gave as examples, read and re-read your explanations, and am pleased that a few things are beginning to make sense. Without bothering you with more details, I am, saying to myself the ff:

      As explained by you, Get-Member returns those properties, methods, etc.. on each line/record (you call them 'items', the book of Hicks and Jones calls them 'rows') as they "come down the pipe" one-by-one, denoted by the "$_" symbol. So Get-Member in expectation of a "count" on a single line/record makes no sense: at least not in the context of my stated problem, which is to count all these lines/records (items). But it wasn't until your example command: {Get-Member -INPUTOBJECT $values} in your reply that "something finally made sense". This command displayed COUNT as an AliasProperty, and in comparing its results with just $values | GM, it gave me an understanding of the difference between objects that are collections/arrays versus objects that are lines/records (you call them items).

      I cannot thank you enough for your generous sharing of Powershell knowledge and concepts.
      Sincerely,

You must be logged in to reply to this topic.