配列をユニークにしてその個数とともに返せ

配列をユニークにしてその個数とともに返せ。
具体的には、["foo", "bar", "foo", "baz", "bar", "foo"] を、[ ["foo", 3], ["bar", 2], ["baz", 1] ] にする。

golf - babie, you're my home

考える道筋を全部書いてみます。
(1) 配列を表示させます。

a = ["foo", "bar", "foo", "baz", "bar", "foo"]
a.each do |e|
  puts e
end

(1)の実行結果です。

foo
bar
foo
baz
bar
foo

(2) Hashを使って要素の数を数えます。

h = Hash.new(0)
a = ["foo", "bar", "foo", "baz", "bar", "foo"]
a.each do |e|
  h[e] += 1
end
h.keys.each do |k|
  puts "#{k} => #{h[k]}"
end

(2)の実行結果です。

baz => 1
foo => 3
bar => 2

(3) Hashを元にして結果の配列を構成します。

h = Hash.new(0)
a = ["foo", "bar", "foo", "baz", "bar", "foo"]
a.each do |e|
  h[e] += 1
end
r = []
h.keys.sort.each do |k|
  r << [ k, h[k]]
end
p r

(3)の実行結果です。

[["bar", 2], ["baz", 1], ["foo", 3]]

(4) 問題文に示されている結果とずれていることに気づいたので、元配列の初出順にした。

h = Hash.new(0)
a = ["foo", "bar", "foo", "baz", "bar", "foo"]
a.each do |e|
  h[e] += 1
end
r = []
a.each do |k|
  next unless h[k]
  r << [ k, h[k]]
  h[k] = nil
end
p r

(4)の実行結果です。でもぜんぜんgolf(プログラムサイズをできるだけ小さく)じゃない。

[["foo", 3], ["bar", 2], ["baz", 1]]

(5) 発想を変えてArray#mapを使ってみることにします。まず、ri Array#mapを見て使い方を練習しましょう。

a = ["foo", "bar", "foo", "baz", "bar", "foo"]
b = a.map do |e|
  [ e, 1 ]
end
p b

(5)の実行結果です。

[["foo", 1], ["bar", 1], ["foo", 1], ["baz", 1], ["bar", 1], ["foo", 1]]

(6) いやいや(5)の発想は方向が間違っているような気がします。h[e]の値を調べることで初出リストをkに作ってみました。

a = ["foo", "bar", "foo", "baz", "bar", "foo"]
h = Hash.new(0)
k = []
a.each do |e|
  k << e if h[e] == 0
  h[e] += 1
end
b = k.map do |e|
  [ e, h[e] ]
end
p b

(6)の実行結果です。

[["foo", 3], ["bar", 2], ["baz", 1]]

ぜんぜんgolfじゃないけれど、何となく落ち着いちゃったからいいや(←投げやり)。
追記:
(A) 田中“ハルヒコスプレイヤー”ばびえ嬢の解答が出てきました

%w|foo bar foo baz bar foo|.inject(Hash.new 0){|r,e|r[e]+=1;r}.to_a

(B) とりあえず(A)の結果をpしてみましょう。

p %w|foo bar foo baz bar foo|.inject(Hash.new 0){|r,e|r[e]+=1;r}.to_a

(B)の実行結果です。警告(warning)が出てます。

a.rb:1: warning: parenthesize argument(s) for future version
[["baz", 1], ["foo", 3], ["bar", 2]]

(C) 1バイト増えるのを我慢して括弧を付けましょう。

p %w|foo bar foo baz bar foo|.inject(Hash.new(0)){|r,e|r[e]+=1;r}.to_a

(C)の実行結果です。

[["baz", 1], ["foo", 3], ["bar", 2]]

(C)にコメントを入れてみました。かえってわかりにくくなっちゃった。

p(              # では、何を表示するかというと…
  %w|
    foo bar foo baz bar foo
  |.            # %w|...|は文字列を空白で区切って配列を作ります。
  inject(       # で、その配列にinjectするんですが、
    Hash.new(0) # まず最初にHashオブジェクトを作ります。デフォルト値は0です(これはカウント値の初期値ということ)
  ) { |r, e|    # 作ったHashオブジェクトはrを使って連綿と渡されていきます。eには配列の要素が毎回入って処理が繰り返されます。
    r[e] += 1;  # で、今回のeの処理。カウントを1個増やします。
    r           # 更新したHashオブジェクトを「次」に渡します。
  }.            # で、injectメソッドの戻り値は(すべての要素が反映された後の)Hashオブジェクトになる。
  to_a          # それを配列に返したもの
)               # …を表示するのですね。