ひがきの日記

2013-02-09

解答例 ─ Ruby初級者向けレッスン 44回

第56回 Ruby/Rails勉強会@関西 での Ruby初級者向けレッスン 44回 の解答例 *1

演習問題 1

0 から 9 までの数値をもつ配列 a がある。
a = (0..9).to_a
a # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. 各要素を順番に表示しよう。
  2. 各要素を 2倍した値を持つ配列を作ろう。
  3. 全要素の合計値を計算しよう。
  • スライドのおさらい。
  • 改めてやってみると、意外とできないかも知れないよ。
# -*- coding: utf-8; -*-

# 0 から 9 までの数値をもつ配列 a がある。
a = (0..9).to_a         # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


# 各要素を順番に表示しよう
a.each{|i| puts i}

# >> 0
# >> 1
# >> 2
# >> 3
# >> 4
# >> 5
# >> 6
# >> 7
# >> 8
# >> 9


# 各要素を 2倍した値を持つ配列を作ろう
a.map{|i| i * 2}  # => [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]


# 全要素の合計値を計算しよう
a.inject{|s, i| s + i}      # => 45

## マニアが書くと
a.inject(:+)                # => 45

演習問題 2

0 から 9 までの数値をもつ配列 a がある。
  • パズルだと思って、いろいろやってみよう。
# -*- coding: utf-8; -*-

# 0 から 9 までの数値をもつ配列 a がある。
a = (0..9).to_a       # => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


# 奇数の要素だけを持つ配列を作ろう
a.select{|i| i.odd?}            # => [1, 3, 5, 7, 9]


# ただし odd? メソッドは使用禁止


# 2 で割った余りが 1 なら奇数
a.select{|i| i % 2 == 1}        # => [1, 3, 5, 7, 9]


# 偶数でなければ、それは奇数
a.select{|i| !i.even?}          # => [1, 3, 5, 7, 9]


# rubyist は true/false の否定を嫌う
# reject は式が真の要素を捨て去る
a.reject{|i| i.even?}           # => [1, 3, 5, 7, 9]

## マニアが書くと
a.reject(&:even?)               # => [1, 3, 5, 7, 9]

マニアのコードに出てきた & は、スライドに登場した、ブロックの受け渡しに使う & とは少し違う。*2


演習問題 3

Enumerable#map を自作してみよう。
module Enumerable
  def my_map
    ……
  end
end
ただしEnumerable#map とEnumerable#map! は使用禁止。

会場には「mapが使えないなら collectを使えばいいじゃない」と言う人がいた。
こういうことですね。わかります。*3

module Enumerable
  def my_map &block
    collect(&block)
  end
end

a = [*0..4]             # => [0, 1, 2, 3, 4]

a.map{|i| i * 2}        # => [0, 2, 4, 6, 8]
a.my_map{|i| i * 2}     # => [0, 2, 4, 6, 8]
a.map                   # => #<Enumerator: [0, 1, 2, 3, 4]:map>
a.my_map                # => #<Enumerator: [0, 1, 2, 3, 4]:collect>

惜しい。
多くのブロック付きメソッドはブロックを渡さないと Enumerator を返す。
my_map の方は #<Enumerator: ... :collect> になっちゃってる。

# -*- coding: utf-8; -*-

# Enumerable#map を自作してみよう
# ただし Enumerable#map と Enumerable#map! は使用禁止

module Enumerable
  def my_map
    unless block_given?
      # ブロックがもらえなかったら Enumerator を返す
      to_enum __callee__
    else
      # 空の Array を用意し、
      inject([]) do |result, item|
        # ブロックの評価結果を追加する
        result << yield(item)
      end
    end
  end
end

# 試してみる
a = [*0..3]           # => [0, 1, 2, 3]

# map と my_map の比較
a.map{|i| i * 2}      # => [0, 2, 4, 6]
a.my_map{|i| i * 2}   # => [0, 2, 4, 6]

# Enumerator も比較
i = a.map             # => #<Enumerator: [0, 1, 2, 3]:map>
j = a.my_map          # => #<Enumerator: [0, 1, 2, 3]:my_map>

i.next                # => 0
i.next                # => 1
i.next                # => 2
i.next                # => 3

j.next                # => 0
j.next                # => 1
j.next                # => 2
j.next                # => 3
j.next                # => 

# ~> -:40:in `next': iteration reached an end (StopIteration)
# ~> 	from -:40:in `<main>'

詳しくは、時間がとれたら書きたい。*4

*1:There's More Than One Way To Do It. もっといいやり方があったら教えて。

*2:どう違うかはうまく説明できない。><

*3:これも反則です。

*4:コメントいただければ可能な限りお答えしたい。

2011-07-19

tweet した写真が消せなくて涙目

f:id:mas-higa:20110718172307j:image:w360

RubyKaigi2011 最終日、Heroku主催のパーティーに reject されて 30 人くらいで居酒屋へ。
しばらくすると matz が登場。写真撮影会となる。*1

翌日とある方が matz との写真について tweet していたので「私もあなたと matz の写真撮りましたよ」的な mention をしてしまった。

その後「人の顔写真晒すとかなんなの」的な展開になり写真を消すことに。

幸い fav もされてないし消せるよね …… って tweet よりも写真を消さなあかんやろ!

写真はいったいどこにポストされたのか?


lockerzって?

リンクを見ると lockerz とかいうのを使ってるらしい。

写真を消すには、たぶんログインするんだろうけど、ユーザ登録とかした覚えない。

ググッてみると元は plixi とかいうサービスだったらしい。

でも plixi もユーザ登録した覚えない。

twitter には Echofon ってアプリでアクセスしてるので、ユーザ登録も Echofon がしてくれたのか?

ログインできないので FORGOT PASSWORD? のリンクを辿ってみたけど、考えつく全てのメールアドレスを試してみても、そんなメールアドレス知らんとか言われて先に進まない。

このまま写真消せなかったら、twitter アカウント消して雲隠れするしかない。

f:id:mas-higa:20110724213859j:image:w360

ダメもとで新しいアカウントを作って twitter アカウントと連携してみたら、その新しいアカウントで写真を削除できた。

非常に焦った。

*1:私と matz の写真をお持ちの方はご連絡ください。

2011-07-16

最後の RubyKaigi に行ってきた

f:id:mas-higa:20110718173400j:image:w360

RubyKaigi 参加は今年で 2 回目。

去年は当日スタッフで参加したけど、今年は一般で参加した。*1
その代わりと言ってななんだけど、今年も個人スポンサーには応募した。

一年ぶりに Ruby 界で著名な方々にお会いした。

中には私のことを覚えてくれてる方がいて、

  • Instagram の人ですよね。
  • いつも Instagram で「いいね」ありがとうございます。

などのお言葉をいただいた。

会議の動画は vimeo.com で見られるようだ。

やっぱり RubyKaigi は刺激になる。ってか刺激が強すぎてヘコむ。


闇Ruby会議

  • 例年の Reject会議のようなもの。
  • 要 teenage spirit

「きんつばスイーツの会」としてエントリしていた @no6v さんが参加できなくなったため代打でやることになった。*2

前日の夜は半泣きでスライドを作成。

元々 @no6v さんは「参加できないかも」とか言っていたので、こうなるんじゃないかと思いつつ、何も言い出せない闇Rubyistっぷり。

ステージの上から @kakutani さん、@jugyo さんに関西Ruby会議04のオファーをしろ! と指令を受けていたのだが、なんか無駄なことを喋ってるうちに時間がなくなって、一番大切な所がグダグダになってしまった。*3

関西Ruby会議04

そんな訳で関西Ruby会議04を計画中。

関西オープンソースでは協賛企業を募集中。

詳しくは info2011(a)k-of.jp まで。

*1:もうトシなんで 3 日間立ちっぱなしとか無理。

*2:@muryoimpl さん、@spring_aki さんと一緒にステージに上がった。@morphine57 さんには裏切られた。

*3:LT 形式でオチを最後に残すなんて高度な技を要求されても……

*4:関西ではこのイベントがメイン。

2010-10-14

練習 3-2

`cmd` を使って文字列を作る練習問題。

前回の修正

前回のをちょっと修正。

puts `ls -la | awk 'NF==9{printf("%s, %d\\n", $9, $5)}'`
# >> ., 3366
# >> .., 204
# >> .bash_history, 507123
# >> .bash_profile, 16
# >> .bashrc, 1188
    ...

NF==9 がないとゴミが出る。*1

ただしファイル名に空白が入っていると表示されなくなる。(マテ)


発展形

puts `ruby -e 'puts Dir.open(".").map{|f|"\#{f}, \#{File.size(f)}"}'`
# >> ., 3366
# >> .., 204
# >> .bash_history, 507123
# >> .bash_profile, 16
# >> .bashrc, 1188
    ...

エスケープがややこしいですね。

冗談はこのくらいにして、


模範回答

と思われるものを

puts `ls -la`.
  split(/\n/).
  map{|i|i.strip.split(/\s+/, 9)}.
  reject{|i|i[8].nil?}.
  map{|i|i.values_at(-1, 4).join(', ')}
# >> ., 3366
# >> .., 204
# >> .bash_history, 507123
# >> .bash_profile, 16
# >> .bashrc, 1188
    ...

9 とか 8 とか 4 とか -1 とか気になる。

では、こうか

LSLong = Struct.new(:perm, :ln, :uid, :gid, :size, :mon, :mday, :year_time, :name)
puts `ls -la`.
  split(/\n/).
  map{|i|LSLong.new(*i.strip.split(/\s+/, LSLong.members.size))}.
  reject{|i|i.name.nil?}.
  map{|i|"#{i[:name]}, #{i[:size]}"}

やっぱりディレクトリ/ファイルの処理は Dir, File, FileUtils なんかを使う方が簡単。

*1:実際の結果を貼ってないから気付かなかった。

2010-07-24

第45回 Ruby/Rails勉強会@関西に行ってきた

第45回 Ruby/Rails勉強会@関西

演習問題をやってみた

正の整数 n の階乗 n! を求める方法を何通りでも考えてください

class Integer
  def !
    case self
    when 0, 1
      1
    else
      self * (self-1).!
    end
  end
end
# とか
class Integer
  def !
    (1..self).inject(1, &:*)
  end
end

0.!         # => 1
1.!         # => 1
2.!         # => 2
3.!         # => 6
4.!         # => 24

inject の初期値を 1 にするのは、いつものように id:no6v に教えてもらった。

文字列 "零 一 二 三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五" があります。これから次のような日本語の漢数字の読みを表すハッシュテーブルを作ってください。

"零 一 二 三 四 五 六 七 八 九 十 十一 十二 十三 十四 十五".split(/\s+/).
  each_with_index.inject(Hash.new){|h, a|h[a[1]]=a[0];h}
# >> {0=>"零",  1=>"一",  2=>"二",  3=>"三",  4=>"四",  5=>"五",
# >>  6=>"六",  7=>"七",  8=>"八",  9=>"九",  10=>"十",  11=>"十一",
# >>  12=>"十二",  13=>"十三",  14=>"十四",  15=>"十五"}

シンボルの配列 syms があります。これを先頭だけ大文字化され、昇順にソートされた文字列の配列に変えてください。

syms = [:tokyo, :kyoto, :osaka, :kobe, :matze, :sendai]

syms.map{|i|i.to_s.capitalize}.sort
# => ["Kobe", "Kyoto", "Matze", "Osaka", "Sendai", "Tokyo"]

正の整数 n の二重階乗 n!! を求めるメソッドを書いてください。

class Integer
  def factorial2
    step(1, -2).inject(1, &:*)
  end
end

(0..9).map(&:factorial2)
# => [1, 1, 2, 3, 8, 15, 48, 105, 384, 945]

残念ながら !! という名前のメソッドは作れない。

n までの整数からすべての合成数を除いて素数だけを残すやりかたとして「エラトステネスのふるい」というアルゴリズムが有名です。このアルゴリズムをイテレータを使ってうまく実装してください。

require 'prime'
class Integer
  def eratosthenes
    Prime::EratosthenesGenerator.new.inject([]) do |prime, i|
      return prime  if i > self
      prime << i
    end
  end
end

20.eratosthenes     # => [2, 3, 5, 7, 11, 13, 17, 19]

冗談です。

class Integer
  def eratosthenes
    (2..Math.sqrt(self).to_i).
      inject((2..self).to_a) do |sieve, prime|
      sieve.reject{|i|i > prime && i % prime == 0}
    end
  end
end

20.eratosthenes     # => [2, 3, 5, 7, 11, 13, 17, 19]

次のメソッドは二項分布を生成します。これを改良してください。ちなみに二項分布は次のように試行回数 n と確率 p をパラメータとする確率分布です。ここでは二項係数 nCx を計算するのにパスカルの三角形を構成して使っています。

[あとで書く] かも