fizz buzz question

This topic contains 8 replies, has 2 voices, and was last updated by Profile photo of Глеб Боушев Глеб Боушев 8 months, 1 week ago.

  • Author
    Posts
  • #37082

    so I found this on the web
    1..100|%{$x=@{0='Fizz'}[$_%3]+=@{0='Buzz'}[$_%5];@{0=$x;1=$_}[[Int]!$x]}

    and I can't figure out how it does what it does... 😉 could someone explain please? I understand what the first part does, up to this thing "];@{0=$x;1=$_}[[Int]!$x]}" but I don't really understand how the first part works. I know what % does and += but HOW does it work? and what the second part does and HOW?

    Thank you!

  • #37083
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I'd say this is a lesson in not writing unreadable crap for code. 😉 However, here goes:

    This is really two statements, so let's split them out:

    $x=@{0='Fizz'}[$_%3]+=@{0='Buzz'}[$_%5]
    @{0=$x;1=$_}[[Int]!$x]
    

    The first line doesn't output anything, it just sets up the $x variable, which will be either null, "Fizz", "Buzz", or "FizzBuzz", depending on the value of $_ and whether it is divisible by 3 and/or 5.

    The second line wants to output the number $_ , if $x is null, and otherwise output $x. "!$x" becomes a boolean: if $x is $null, !$x will be true, and if $x any non-empty string, !$x is false. When you cast booleans to [int] in PowerShell, $true becomes 1, and $false becomes 0. The hashtable is set up so that 0 outputs the value of $x, and 1 outputs the value of $_.

  • #37084
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Incidentally, if this is a "code golf" kind of thing where they wanted the code to be short, it can be trimmed a bit:

    1..100|%{$x=@('Fizz')[$_%3]+@('Buzz')[$_%5];($x,$_)[!$x]}
    

    This uses arrays instead of hashtables, and uses "+" instead of "+=". As long as strict mode isn't turned on (which would complain about invalid array indexes), this works the same way. The casting of a boolean to [int] is implicit as well, so you can save a few characters by not typing that part out.

  • #37085

    Hello, thank you, but how does part 1 work, I mean, where can I read something about this @(something). What kind of construction is that?

  • #37086
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    @() is the array subexpression operator. It forces the contents of the parentheses to be evaluated as an array, even if there are 0 or 1 results returned. (If 2 or more objects were there, it would be an array anyway, which is why I was able to do away with the @ character, in the second part.)

    The basic documentation of this is in the about_Operators help file (https://technet.microsoft.com/en-us/library/hh847732.aspx) .

  • #37087

    omg, i'm retarded, sorry!

    But you explained so good that even I understood (that's a rhyme)
    and bear in mind I'm retarded.

    Thank you, case closed!

  • #37088
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Don't worry about it! 🙂 Like I said, this kind of code is garbage that's only useful for code golf contents (and maybe for practice at reading bad code.) In the real world, you want code to be easy to read and understand, first and foremost. Something like this:

    1..100| ForEach-Object {
        $string = ""
    
        if ($_ % 3 -eq 0)
        {
            $string += "Fizz"
        }
    
        if ($_ % 5 -eq 0)
        {
            $string += "Buzz"
        }
    
        if ($string -eq "")
        {
            $string = $_
        }
    
        $string
    }
    
  • #37091

    sorry to bother you, but how in the world does this work?: what do I google? xD

    filter fizz-buzz{
        @(
            $_, 
            "Fizz", 
            "Buzz", 
            "FizzBuzz"
        )[
            2 * 
            ($_ -match '[05]$') + 
            ($_ -match '(^([369][0369]?|[258][147]|[147][258]))$')
        ]
    }
     
    1..100 | fizz-buzz

    is that regex??

  • #37102

    Okay, I got this one, it turned out to be pretty easy, I didn't think they were just bruteforcing this problem, basically. I thought that is some funky command encoding or aliases or something like that. What they are doing is testing if $_ starts with 3,6 or 9 and has 0,3,6,9 or 2,5,8 and 1,4,7 or you get the idea. So if it matches it returns 1 if not 0.
    so we have 2 * (1 or 0) + (1 or 0). That leads to 4 outcomes 0,1,2,3 which equates to

    $_, 
            "Fizz", 
            "Buzz", 
            "FizzBuzz"

    pretty clever, but I thought its something much more complex 😉

You must be logged in to reply to this topic.