観察日記 2018-02-14

配列の全ての要素が等しいか否か

mrkn
配列の全ての要素が等しいことはどう確認したら良いんだろう。
`ary.all? {|e| e == ary[0] }` これかな

usa
ary.uniq.size == 1

mrkn
なるほど > uniq

usa
all?でブロック引数より速そうな予感
いやでもaryがでかくてかつ全然要素が等しくなかったらそうでもないか。

mrkn
`ary.all? {|e| e.foo == ary[0].foo }` の場合はどうでしょう。map.uniq.size がいいかな

usa
all?は全て等しい時に遅いが、序盤で違うとわかったら速い

mrkn
確かに > 序盤で違うとわかったら速い

usa
この辺は予想される集合の傾向で判断するしかないですかねえ。
map.uniq.sizeはmapの結果としての一時配列を作らないようにするには、えーと
Enumerator

mrkn
一瞬 `ary.homogeneous? {|e| e.foo }` って書きたくなったけど、そのまま書いても読めるから大丈夫そうだ。
`ary.lazy.map(&:foo).uniq.size`

naruse
MJITがall?もはやくしてくれるさぁ

mrkn
all? がインライン展開されるのか。

sorah
lazy.uniqいけるのか。
.sizeじゃなくて .count?

usa
lazyだとsizeはまずい

mrkn
lazy 使う場合は count でした

sorah
`[1,1,1,1].lazy.uniq.take(2).count == 1` かなぁ

usa
だいぶテクニカルになってきたな

sorah
>> a = Struct.new(:i) { def n; p i; end }; [a.new(1), a.new(2), a.new(3), a.new(4)].lazy.map(&:n).uniq.take(2).count
1
2
=> 2
>> a = Struct.new(:i) { def n; p i; end }; [a.new(1), a.new(2), a.new(3), a.new(4)].lazy.map(&:n).uniq.count
1
2
3
4
=> 4
こういう差が。 usa なるはや殺しっすよね しかしさすがにここまでくると別名をつけたくなったね。 mrkn take(2) 頭いいな この take(2) は結構感動しました。 usa さすがそらはパイセンですよね。 しかし `homogeneous?` ってわかりやすい名前なのかな。 tadd https://ruby-gnome2.osdn.jp/ja/hiki.cgi?%A5%DC%A5%C3%A5%AF%A5%B9 ruby + homogeneous でぐぐったらGtkが引っかかった mrkn 私が最初に思いついた名前なので、一般的ではないと思います。 ary.same_all? とかかな usa ぼくもsame_allかなあと思いました。 mrkn activesupport にも存在しない knu `[1,1,1,1].each_cons(2).all? { |a,b| a == b }` usa なんとなく遅そうなイメージ knu なぜだろう usa 比較が1回減るのはいいのだけど (e0,e1) (e1,e2) (e2,e3) ... という舐め方が有利なのか不利なのかどっちだろう、という。 knu ブロックが遅い気がする。簡略記法欲しいな usa ブロックはどうしても遅い knu `inject(:+)` はチート 計測すると、条件成立時や末尾に違う値がある場合は uniq が2倍以上速い でも、ショートカットはしてくれないので最初の方に違う値が検出される場合は当然each_consが圧勝 usa 2倍以上かあ。 やはり想定されるデータセットにあわせて選ぶしかないですね。 knu きっとone? があれば lazy.uniq.one? が最適解かな (equality が eql? ってのはおいといて) usa あ、そういうのはまあそういうことで knu ショートカットがないは語弊があった。2つの値だけがずっと続く場合は〜、だ。 one? はたまーにほしいんだよな 何回か前のDeveloperMeetingで出てたか と思ったらある?あれ? usa おっ knu 一つだけが真の場合にtrueを返すのか nilやfalseを考えないなら使えるか `[1,1,1,1].lazy.uniq.one?` でよさそう uniqだから 1 と 1.0 は区別される、one?だから nil や false が入る場合はダメ、という制約付き sorah ブロック無し `.any?` を `.size > 0` 的に使ってるのと同じくらいの生理的嫌悪感がある usa わかる sorah あれ使ってる人は nil, false での動作理解して書いてんのかな、というのが分からなくて混乱するのでやめてほしいんだよな knu お、 `one?(&:object_id)` にしても速度落ちない knu Lispだと=がいくつでも引数取れるか `(apply #'= '(1 1 1 1)) ` ずるい usa ずるいよね knu Rubyのオブジェクト指向はレシーバと引数の間に偉さの違い usa Rubyしぐさ knu zipがたまに気持ち悪い 気持ちは a.zip(b,c) でなく [a,b,c].zip と書きたいんだ… Array.zip(…) が配列を返して Enumerator.zip(…) はEnumerableを返す、というのは悪くないと思うんだけど字面がRubyっぽくないんだよな mrkn 会社のブログで出題してみたら `ary.rotate == ary` というここでは出なかった解が出てきた。 usa おー 遅そうw でも柔軟な発想を感じる。すごい。 mrkn 似たようなので `ary[0..-2] == ary[1..-1]` usa rotateしないからこれはまだ。しかしかっこよさに欠けるな。 いや、これ実はむっちゃ速い? mrkn 配列を作らない usa しかも評価もおそらく短絡してくれる。 mrkn 配列の長さが2以上の時の実装はコレでしょうな。 usa 1の時もいけるのでは ko1 rotate 知らなかった sorah 柔軟な発想だ… usa それを考えた人に今日の :100: をあげよう。 文句なし。

slackのログを上手いことまとめる方法が思いつかなかったので、雑にpreで……。