Author Posts

March 30, 2016 at 5:38 am

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!

March 30, 2016 at 5:45 am

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 $_.

March 30, 2016 at 5:48 am

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.

March 30, 2016 at 5:56 am

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?

March 30, 2016 at 6:00 am

@() 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) .

March 30, 2016 at 6:06 am

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!

March 30, 2016 at 6:10 am

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
}

March 30, 2016 at 6:30 am

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??

March 30, 2016 at 10:25 am

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 😉