47915


ひらがなの文字列の入った配列を、1文字目がどの行（あかさたなはまやらわ）かでグループ分けしたい時、  
どんな実装が考えられますでしょうか？

[code]

    a = %w[あかがい うなぎ ほたて]
    puts group_by_kana_row(a)
    
    # { 'あ'=> ['あかがい', 'うなぎ'], 'は'=> ['ほたて'] }
    
[/code]


CC BY-SA 4.0
2018-08-29T10:20:56.327
47911
2018-11-09T13:31:50.377
2018-08-29T10:35:21.110
9178
9178
question
ruby 日本語
Rubyであかさたなでgroup_by


以下はどうでしょうか?

[code]

    a = %w[あかがい うなぎ ほたて]
    
    group = a.group_by do |item|
      case item[0]
      when /[ぁ-お]/  # ぁ, あ, ぃ, い, ぅ, う, ぇ, え, ぉ, お
        'あ'
      when /[か-ご]/  # か, が, き, ぎ, く, ぐ, け, げ, こ, ご
        'か'
      when /[さ-ぞ]/  # さ, ざ, し, じ, す, ず, せ, ぜ, そ, ぞ
        'さ'
      when /[た-ど]/  # た, だ, ち, ぢ, っ, つ, づ, て, で, と, ど
        'た'
      when /[な-の]/  # な, に, ぬ, ね, の
        'な'
      when /[は-ぽ]/  # は, ば, ぱ, ひ, び, ぴ, ふ, ぶ, ぷ, へ, べ, ぺ, ほ, ぼ, ぽ
        'は'
      when /[ま-も]/  # ま, み, む, め, も
        'ま'
      when /[ゃ-よ]/  # ゃ, や, ゅ, ゆ, ょ, よ
        'や'
      when /[ら-ろ]/  # ら, り, る, れ, ろ
        'ら'
      when /[ゎ-を]/  # ゎ, わ, ゐ, ゑ, を
        'わ'
      else
        item[0] # ん, その他
      end
    end
    
    group                           #=> {"あ"=>["あかがい", "うなぎ"], "は"=>["ほたて"]}
    
[/code]

### 参考

[正規表現を使うときに注意すべきこと#ひらがなの文字コード](https://qiita.com/kokorinosoba/items/78811d7e2b6bc424b1b1#%E3%81%B2%E3%82%89%E3%81%8C%E3%81%AA%E3%81%AE%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89)


CC BY-SA 4.0
2018-08-29T11:01:32.320
47915
2018-08-30T02:13:01.923
2018-08-30T02:13:01.923
29553
29553
47911
answer


同じく、`group_by` を使ってみました。

[code]

    def group_by_kana_row(a)
      keys = 'あかさたなはまやらわん'.chars
      keys_ord = 'ぁかさたなはまゃらゎん'.chars.map{|c| c.ord}
      a.group_by do |item|
        first = item[0].ord; r = 'no_match'
        keys_ord.each_with_index do |k, i|
          next if first > k
          r = keys[(first == k ? i : i-1)]
          break
        end
        r
      end
    end
    
    a = %w[あかがい うなぎ ほたて]
    group_by_kana_row(a)
    {"あ"=>["あかがい", "うなぎ"], "は"=>["ほたて"]}
    
[/code]


CC BY-SA 4.0
2018-08-29T12:12:58.607
47919
2018-08-29T12:12:58.607
47911
answer


考え方は他の方の回答とだいたい同じなんですが、短く書いてみました。  
わかりにくくなってる気もしないでもないですが…。

[code]

    def group_by_kana_row(a)
      keys = "ぁかさたなはまゃらゎん".chars
      a.group_by do |x|
        keys.each_cons(2) do |s, e|
          break s if x < e
        end
      end.transform_keys{|k| k&.tr('ぁゃゎ', 'あやわ') }
    end
    
    a = %w[あかがい うなぎ ほたて]
    p group_by_kana_row(a)
    
[/code]


CC BY-SA 4.0
2018-08-30T16:04:11.500
47949
2018-08-30T16:04:11.500
3249
47911
answer


拡張性を持たしてみました。(`&.`を使っているのでRuby 2.3以上)

[code]

    # frozen_string_literal: true
    
    # Unicode 10.0で追加された変体仮名には未対応
    KANA_ROWS = {
      'あ' => [*(?ぁ..?お), ?ゔ],
      'か' => [*(?か..?ご), ?ゕ, ?ゖ],
      'さ' => [*(?さ..?ぞ)],
      'た' => [*(?た..?ど)],
      'な' => [*(?な..?の)],
      'は' => [*(?は..?ぼ)],
      'ま' => [*(?ま..?も)],
      'や' => [*(?ゃ..?よ), ?\u{1B001}],
      'ら' => [*(?ら..?ろ)],
      'わ' => [*(?ゎ..?を)],
      'ん' => [?ん],
    }
    
    def kana_row(str)
      KANA_ROWS.find { |_, list| str.start_with?(*list) } &.first
    end
    
    def group_by_kana_row(list)
      list.group_by(&method(:kana_row))
    end
    
    a = %w[あかがい うなぎ ほたて だ ゔぃくとりぃ abc]
    puts group_by_kana_row(a)
    
[/code]

※ U+1B001(「」"江"を崩した文字、環境によっては表示されない)はUnicode 6.0で追加された補助仮名で"や行え"です。

平仮名から始まらない場合は`nil`グループとしています。Unicode
10.0で追加された変体仮名に対応したい場合は、`KANA_ROWS`に足していくだけになります。また、片仮名も含める、アルファベットや数字もグループ化するといった拡張もKANA_ROWSに追加することで出来るようになっています(ただ、そのような拡張をする場合は名前は変えた方が良いかもしれない)。


CC BY-SA 4.0
2018-08-31T14:50:37.123
47988
2018-08-31T14:50:37.123
7347
47911
answer

[code]

    def group_by_kana_row(a)
     {
      'あ': a.select{|s| ('あ'..'お').to_a.include?(s[0])},
      'か': a.select{|s| ('か'..'こ').to_a.include?(s[0])},
      'さ': a.select{|s| ('さ'..'そ').to_a.include?(s[0])},
      'た': a.select{|s| ('た'..'と').to_a.include?(s[0])},
      'な': a.select{|s| ('な'..'の').to_a.include?(s[0])},
      'は': a.select{|s| ('は'..'ほ').to_a.include?(s[0])},
      'ま': a.select{|s| ('ま'..'も').to_a.include?(s[0])},
      'や': a.select{|s| ('や'..'よ').to_a.include?(s[0])},
      'ら': a.select{|s| ('ら'..'ろ').to_a.include?(s[0])},
      'わ': a.select{|s| ('わ'..'ん').to_a.include?(s[0])}
     }
    end
    
    group_by_kana_row(%w[あかがい うなぎ ほたて])
    
[/code]


CC BY-SA 4.0
2018-11-09T13:31:50.377
50132
2018-11-09T13:31:50.377
30913
47911
answer