Parameterized Array#uniq (i.e., uniq_by) [duplicat

2019-07-07 04:31发布

This question already has an answer here:

What if instead of removing duplicate elements from an array, I want to remove elements that have a specific property in common?

Specifically, I want to remove all strings from an array with duplicate "essences", where essence is defined like this:

class String
  def essence
    downcase.gsub('&', 'and').gsub(/[^a-z0-9]/, '')
  end
end

I want something like this:

['a', 'A', 'b'].uniq_by(&:essence)
# => ['a', 'b'] (or ['A', 'b']; I don't really care)

What's the best way to accomplish this?

标签: ruby arrays
3条回答
你好瞎i
2楼-- · 2019-07-07 04:56

Activesupport has a Array#uniq_by, and this is the code:

class Array
  def uniq_by
    hash, array = {}, []
    each { |i| hash[yield(i)] ||= (array << i) }
    array
  end
end

Facets also has a Enumerable#uniq_by:

module Enumerable    
  def uniq_by
    h = {}
    inject([]) {|a,x| h[yield(x)] ||= a << x}
  end    
end
查看更多
时光不老,我们不散
3楼-- · 2019-07-07 05:01

Quick and dirty way:

['a', 'A', 'b'].group_by {|i| i.essence}.values.map(&:first)

And some monkey patching:

class Array
  def uniq_by(&block)
    group_by(&block).values.map(&:first)
  end
end
查看更多
劫难
4楼-- · 2019-07-07 05:13

Since 1.9.2, Array#uniq (and uniq!) takes a block, so no more need for uniq_by.

查看更多
登录 后发表回答