从基础说起,可以用一个 Hash 对应一个 Person,一个 Person 数组就是:
persons = [ { name: '李xx', sex: '', tel: '' }, { name: '张', sex: '', tel: '' } ] # and more
数组(Array)内含了不少方法,其中的 inject 方法可以将数组遍历然后计算出一个结果,文档看这里 http://ruby-doc.org/core-2.2.1/Enumerable.html#method-i-inject ,对应你的需求就是:
persons.inject(Hash.new(0)) {|hash, person| hash[person[:name][0]] += 1; hash }
# => { '李' => 1, '张 => 1 }
解释一下,Hash.new(0) 创建一个空 Hash 用来存放结果(这个 Hash 每个 key 的默认值是 0),然后传到 inject block 里面;block 里面的 person[:name][0]
取到用户的姓,然后作为 key 找到 hash 的对应值 += 1;最后 block 要将 hash 作为结果返回作为下一次迭代的 hash 值,遍历完毕后 hash 就是你要的结果。
如果你希望 Person 成为一个类,方法差不多,代码变为:
class Person
# attr_accessor 定义了 getter setter 方法
attr_accessor :name, :sex, :tel
def initialize(attributes)
@name = attributes[:name]
@sex = attributes[:sex]
@tel = attributes[:tel]
end
end
persons = [ Person.new( name: '李xx', sex: '', tel: ''), Person.new( name: '张xx', sex: '', tel: '') ]
persons.inject(Hash.new(0)) {|hash, person| hash[person.name[0]] += 1; hash }
以上是 Ruby 的做法,你问到了 Rails 的做法,那么假设数据是存在数据库里的,并且使用了 ActiveRecord,那么可以通过数据库查询得出:
class Person < ActiveRecord
end
# PostgreSQL 语法
Person.select('substring(name for 1) as first_name, count(*)').group('first_name').map{ |person| [person.first_name, person.count] }.to_hash