1| numbers = [1 ,2, 3, 4, nil, 5, nil, 7]
2| numbers.each do |number|
3| puts number unless number == nil
4| end
よく上のようなプログラムを書くのですが、
3行目のような「ある条件のときだけ表示をする」というケースで
変数が二回出てくるのがなんか気持ち悪いです。
もっとスッキリ書く方法はありますでしょうか?
「Array#compactをする」のような回答を望んでいるわけではなく、
3行目をスッキリ書くやりかたが知りたいです。
よろしくお願いします。
おっしゃりたい事は、たぶん、
ような書き方はできないか?という事ですね。
組み込みの関数や制御構造にはそのようなものはないようです。
それでも、もしあえてやるとすると、自分で定義する事になると思います。
例えば、putsに特化するなら、
def putsnn(n) puts n if n end numbers = [1, 2, 3, 4, nil, 5, nil, 7] numbers.each do |number| putsnn number end
任意のブロックやメソッドに対応するなら、
def donn(n) yield n if n end numbers = [1, 2, 3, 4, nil, 5, nil, 7] numbers.each do |number| donn number,&method("puts") end
後者の場合、たまたまputsはKernelモジュールのメソッドで、奇麗な形には書けないと思うのですが、生憎、私もまだRuby初心者ですので、本当はもっといい書き方があるかもしれません。
これが一番すっきりかつ明瞭だと思います。
numbers = [1 ,2, 3, 4, nil, 5, nil, 7] numbers.each do |number| puts number if number end # >> 1 # >> 2 # >> 3 # >> 4 # >> 5 # >> 7
numbers = [1 ,2, 3, 4, nil, 5, nil, 7] numbers.map{|x|puts x if x}
これでどうでしょうか
あるいは先に配列から条件にあうものを消しておくとか
numbers = [1 ,2, 3, 4, nil, 5, nil, 7] numbers.delete(nil) numbers.each do |number| puts number end
おっしゃりたい事は、たぶん、
ような書き方はできないか?という事ですね。
組み込みの関数や制御構造にはそのようなものはないようです。
それでも、もしあえてやるとすると、自分で定義する事になると思います。
例えば、putsに特化するなら、
def putsnn(n) puts n if n end numbers = [1, 2, 3, 4, nil, 5, nil, 7] numbers.each do |number| putsnn number end
任意のブロックやメソッドに対応するなら、
def donn(n) yield n if n end numbers = [1, 2, 3, 4, nil, 5, nil, 7] numbers.each do |number| donn number,&method("puts") end
後者の場合、たまたまputsはKernelモジュールのメソッドで、奇麗な形には書けないと思うのですが、生憎、私もまだRuby初心者ですので、本当はもっといい書き方があるかもしれません。
再回答ですが、これが何かすっきりした感じです。
numbers = [1 ,2, 3, 4, nil, 5, nil, 7] puts numbers.reject{|x|x==nil}
Rubyらしくは・・・
#こんなのダメだと怒られそうですが
numbers = [1 ,2, 3, 4, nil, 5, nil, 7] numbers.each do |number| puts(number||next) end
「ある条件のときだけ表示をする」
を
「ある条件を満たす要素の配列を生成して」「その配列の全要素を表示する」
と書き換えれば Array#select が標準で用意されていますから
[1, 2, 3, 4, nil, 5, nil, 7].select{|x| x != nil}.each{|x| puts x}
と(条件の如何に関わらず)書けると思います。
もっとも、このパターンで「条件」が「要素がnilでない」ケースが Array#compact ですから
ご質問の趣旨に沿う回答になっているかどうか、自信はないのですが。
コメント(14件)
f = lambda {|x| puts x if x}
numbers.each do |number|
f[number]
end
無理やり一回にしてみます・・・
numbers = [1 ,2, 3, 4, nil, 5, nil, 7]
numbers.select{|x| x != nil}.each do |number|
puts number
end
||<
numbers.select{|x| x != nil}.each do |number|
こういうのを一言で書けるeach_with_condition みたいなのがあるといいかも知れないですね。
http://yowaken.dip.jp/tdiary/20070604.html
module Enumerable を拡張するとできるかも知れないけど、
2つのブロックを引数に取らないといけないのが難しそうです
http://www.rubyist.net/~matz/20070512.html#p04
http://d.hatena.ne.jp/sumii/20070521/p1#c1179813427
rubyでは2つのブロックを渡すのはできない(?)かもです。
#lambdaとかProcを使えばできるのだろうか???
現に「if 式」は「式がnilやfalseではないならば」という意味の頻出イディオムです。
> 変数が二回出てくるのがなんか気持ち悪いです。
という感覚がわからないんですよね…。
"puts number" は「何をするか」だし、
"unless number == nil" は「どういう時にするか」でしょ。
本質的に違うものじゃないですか。
だから、number が一行に二回出てきても全然気持ち悪くないんですよね、わたしは。
例えば今回のArrayの例で言えば、Array#compact等を使うわけです:そのためにそのメソッドはあるのです。
それを忌避すると、私の回答例のようにかえって美しくなくなったりわかりにくくなったりします。
(もちろん、そういうコンストラクトが言語に備わっていればなおいいのではないか、という意見を否定するつもりもありません)
Ruby界隈では「大クラス主義」なんていう言葉もあります。
numbers = [1 ,2, 3, 4, nil, 5, nil, 7]
puts numbers.compact
一つの行のシンプルさのためにその行だけ追求するより、
やっぱり、プログラム全体を見た方が結果的には全ての行がシンプルになります。
□ x if x
で十分なんだけど
これをx一回で済ます構文はあるかという問題ですね。
numbers.each do |number|
proc{|x| puts x if x}[number]
end
出来た。少なくともnumberは1回しか使われていない。
> 卓袱台引っ繰り返しちっくな感想ですが、
> > 変数が二回出てくるのがなんか気持ち悪いです。
> という感覚がわからないんですよね…。
ひょっとすると、
puts nil
が
"nil"
を出力するのが気持ち悪いという意味かもしれませんよ。
その感覚なら、理解できなくもないです。
つまり、「nilの時はむしろ何もしないで欲しい」という気持ちかもしれません。
質問者のコメントや返答が全くありませんので、推測ですが。
ただ、RubyやLL的には、むしろ何かしてくれたほうがうれしい:
何かをさせない事は容易にできるけど、
はじめから何もしないものに対して、新しい何かを付け加えるほうが面倒ですから。
numbers.each do |$_|
print if $_
end
改行なしでいいならこれで。
みなさま、回答・コメントどうもありがとうございました。
予想以上の反応をいただいて、とても驚いています。
さて、質問文がわかりにくくて混乱させてしまったようですが、
質問したかったことは、
「ifで判定しているものと、判定した結果 処理されるものが同じ場合に
ifの判定が真だったもののみを実行する、シンプルな文法はありますか?」
ということでした。 # まだわかりにくいですね…
たとえば日本語でいうと「●●が正しかったら、●●を出す」ではなくて、
「正しいときだけ●●を出す」のようなニュアンスでスッキリ書きたいというのが、
質問の意図に近いかもしれません。 # 余計わかりにくくなったかも…
なので、質問文で「Array#compactではなく」と書いたのは、
チェックでNGになるものも混ぜておかないと
「正しいときだけ●●を出す」のような回答が得られないのでは、と思ったからでした。
実務で使うときは、たぶん躊躇なくArray#compactすると思います(笑)
僕はRubyを使い始めてまだまだ日が浅いのですが、
その短い経験の中でも「こんなにすっきり書けるのか!」という感動を
幾度も味わってきたので、もしかしたらRubyなら…と根拠なく思って質問してみました。
最後になりますが、みなさまの回答を読んで
あらためて自分の勉強不足を痛感し、またRubyの深さも垣間見ました。
これからも何度か質問させていただくことがあると思いますが、
よろしくお願いします。
考えてみたのですが
「正しいときだけ●●を出す」のようなニュアンスでスッキリ書きたい
1. 「正しい」の定義がケースバイケースで●●に依存してしまうので、●●がこれこれならば正しい、という記述が必要
2. ●●を出す、という記述も必要
で 1 については任意の条件を記述できるという話になれば、どうしても引数(?)に●●相当が現れざるをえないでしょ
うし、2についても「出す」への引数に●●相当が現れる、ということで、rubyに限らずプログラムの字面上●●相当が少
なくとも2回出てくるのはしょうがないような気がしてきました。
出す(正しい(●●))
みたいに書けば字面上は●●は1回しか現れませんが、「正しい」というフィルタを定義するのに仮引数が必要になります
(正しい = lambda (x) { x!=nil} とか)ので、本質的には回避策にならないですよね(私の回答がこれ)。たまたま
Array#compactのように組み込み機能が使えれば字面上では●●が1個だけで済むこともありますけれども、それは偶然に
過ぎないわけですし。
yield使って書いてみました。
numbers = [1 ,2, 3, 4, nil, 5, nil, 7]
def foo(cond)
yield(cond) if cond
end
numbers.each do |number|
foo(number){|x|puts x}
end