challenge 変形Fizz-Buzz問題

どもraynstardです。
どちらにしようか迷いましたが発想の元ネタがUIさんの投稿からなので
こちらに投稿してみます。
--------------
以下の仕様を満たす文字列を
20行出力するプログラムを作成してください。

1. 1行の出力は「<行番号> ':' <メッセージ>」であること。
2. 行番号が 3の倍数であるとき、メッセージは「Fizz」であること
3. 行番号が 5の倍数であるとき、メッセージは「Buzz」であること
4. 行番号が 3の倍数かつ5の倍数であるとき、メッセージは「FizzBuzz」であること
5. 上記に記した条件以外のメッセージについては「hoge」であること
6. 条件分岐する場合、if文のみが使用でき、
   かつ、論理式が成立した場合の処理のみが記述できます。
#アセンブリなどifがなければif以外でもかまわないです。(意味が同じならば)

というわけでこの問題はFizz-Buzz問題をelseなしならどう書く?という問題です。

出力例:
 1:hoge
 2:hoge
 3:Fizz
 4:hoge
 5:Buzz
 6:Fizz
 7:hoge
 8:hoge
 9:Fizz
10:Buzz
11:hoge
12:Fizz
13:hoge
14:hoge
15:FizzBuzz
16:hoge
17:hoge
18:Fizz
19:hoge
20:Buzz

Posted feedbacks - Ruby


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def fizzbuzz(n)
  (1..20).each do |i|
    printf("%2d:", i)
    print "Fizz" if i % 3 == 0
    print "Buzz" if i % 5 == 0
    print "hoge" if (i % 3) * (i % 5) != 0
    puts
  end
end

fizzbuzz(20)

こんな感じ?

プレビューのハイライトが間違っている気がする…

“else”は論理の否定を取ってしまうと普通に書けてしまうので,
条件分岐の条件を数以外で行うことと,
“return”で飛んでみるという変形をしました.

""はStringと+について単位元なので,
9行目を変えれば“7の倍数の時は…”
とか別の変形に応用できそうですね.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class String
  def hoge
    return "hoge" if self.empty?
    self
  end
end

1.upto(99) {|i| ## とりあえず99まで
  puts("%2d:%s"%[i,((["Fizz"]+[""]*2)[i%3]+(["Buzz"]+[""]*4)[i%5]).hoge])
}

ああ,なるほど,もしかしたら,
出題者の意図としてはこっちのコードの方が合っているかもしれないな.
他の方のコードをいくつか見て思った.
1
1.upto(20){|i|puts("%2d:%s"%[i,(["FizzBuzz"]+["hoge"]*2+["Fizz","hoge","Buzz","Fizz"]+["hoge"]*2+["Fizz","Buzz","hoge","Fizz"]+["hoge"]*2)[i%15]])}

すでに同じネタ出てるか確認してないのですが。
周期の全部書けばいいじゃん、みんな大げさだなあ、ということで。
1
2
3
4
5
6
7
a = ['hoge', 'hoge', 'Fizz', 'hoge', 'Buzz',
     'Fizz', 'hoge', 'hoge', 'Fizz', 'Buzz',
     'hoge', 'Fizz', 'hoge', 'hoge', 'FizzBuzz']

100.times{|i|
  printf("%2d:%s\n", i+1, a[i%a.size])
}


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def fizzbuzz(n)
  a=[["FizzBuzz","Fizz"],["Buzz","hoge"],[3,5]]
  (1..n).each {|i|
    printf("%2d:%s\n",i,
           a[-1].inject(a) {|r,j|r=r[i**(j-1)%j]}
           )
  }
end

if __FILE__ == $0
  fizzbuzz(20)
end

安直に書いてみました
1
2
3
4
5
6
7
(1 .. 20).each do |i|
  out = ''
  out << 'Fizz' if (i % 3) == 0
  out << 'Buzz' if (i % 5) == 0
  out = 'hoge'  if out.empty?
  puts "%2d:%s" % [i, out]
end

条件分岐無し,剰余演算子無し,ループ無し.
ループ無しという割には,イテレータ付きgsubを
使っているあたりが反則っぽいけど.
1
2
3
4
5
6
7
8
i = 0
print ('o' * 20).gsub(/./) {
  i += 1
  "%2d:%s\n" % [i, '-' * i + ',' + '=' * i]
}.gsub(/:(---)+,/, ':Fizz,').
  gsub(/,(=====)+$/, 'Buzz').
  gsub(/[-=,]/, '').
  gsub(/:$/, ':hoge')

出遅れたけど,こんなのどうか。
1
2
3
4
5
6
fizzbuzz = { true  => { true => "FizzBuzz", false => "Fizz" },
             false => { true => "Buzz",     false => "hoge" } }

1.upto(20) do |x|
  printf("%2d:%s\n", x, fizzbuzz[x%3==0][x%5==0])
end

完璧に出遅れで題意に従っているかあやしいのですが書いてみました。オブジェクト指向 (笑) という感じです。

言語組みこみの if/else を使わないという解釈です。

else にみえるのは、メソッドの名前なので hoge でも fuga でもよく、名前はこのさいどうでもいいと思ったので else のままにしてあります。

cycle を使っているので ruby1.9 です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class True
    def then
        yield
        self
    end

    def else
        self
    end
end

class False
    def then
        self
    end

    def else
        yield
    end
end

t = True.new
f = False.new
(1..20).zip([f, f, t].cycle, [f, f, f, f, t].cycle).each do |i, i3, i5|
    t = ""
    i3.then {
        i5.then {
            t = "FizzBuzz"
        }.else {
            t =  "Fizz"
        }
    }.else {
        i5.then {
            t = "Buzz"
        }.else {
            t = "hoge"
        }
    }
    puts "%2d:%s" % [i, t]
end

せっかく Ruby なので、もうすこし踏みこんで 1.8 系でも動くようにしました。

TrueClass/FalseClass は true/false のクラスで、それを拡張しています。.result を付けくわえたのは if 文 (のようにみえるもの) が値を持つようにみせかけたかったからです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!ruby -Ku
require "pp"

class TrueClass
    def then
        @ret = yield
        self
    end

    def else
        self
    end

    def result
        @ret
    end
end

class FalseClass
    def then
        self
    end

    def else
        @ret = yield
        self
    end

    def result
        @ret
    end
end

(1..20).each do |i|
    puts "%2d:%s" % [i,
        (i % 3 == 0).then {
            (i % 5 == 0).then {
                "FizzBuzz"
            }.else {
                "Fizz"
            }.result
        }.else {
            (i % 5 == 0).then {
                "Buzz"
            }.else {
                "hoge"
            }.result
        }.result
    ]
end

見掛け上は条件分岐を使わず, かつ, FizzとBuzzがコード中に一回ずつしか出現しないようにしてみました. 
1
2
3
4
1.upto(20){|i|
  puts({0 => "#{i}: hoge", i%5 => "#{i}: ", i%3 => "#{i}: Fizz"}.
         merge({i%5 => 'Buzz'}){|k,a,b| "#{a}#{b}"}[0])
}

Index

Feed

Other

Link

Pathtraq

loading...