据我所知,
我的问题是:
如何使 ["a", "A"].uniq 返回 ["a"] 或者 ["A"]?
的结果是
["a", "A"].uniq
is
["a", "A"]
我的问题是:
如何使 ["a", "A"].uniq 返回 ["a"] 或者 ["A"]?
还有另一种方法可以做到这一点。您实际上可以将一个块传递给uniq
或uniq!
,该块可用于评估每个元素。
["A", "a"].uniq { |elem| elem.downcase } #=> ["A"]
或者["A", "a"].uniq { |elem| elem.upcase } #=> ["A"]
在这种情况下,所有字符大小写都不敏感,因此它将始终返回数组["A"]
首先要使大小写一致。
例如:
["a","A"].map{|i| i.downcase}.uniq
编辑:如果像mikej建议的那样,返回的元素必须与原始数组中的完全相同,则以下代码将为您实现此操作:
a.inject([]) { |result,h| result << h unless result.map{|i| i.downcase}.include?(h.downcase); result }
编辑2 可以满足mikej的解决方案 :-)
downcased = []
a.inject([]) { |result,h|
unless downcased.include?(h.downcase);
result << h
downcased << h.downcase
end;
result}
您可以建立一个映射(哈希)来将大小写规范化(例如,转为小写)的值与实际值对应起来,然后仅从哈希中获取值:
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element ; h }\
.values
["A", "b", "C"]
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element unless h[element.downcase] ; h }\
.values
["a", "A"].map{|x| x.downcase}.uniq
=> ["a"]
或者
["a", "A"].map{|x| x.upcase}.uniq
=> ["A"]
['A','a'].uniq_by(&:downcase) # => ['A']
有一种更为高效的方法是在哈希表中使用唯一键,因此请查看以下内容:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] = j; hash}.values
["A"]
当使用 ||= 作为赋值运算符时:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] ||= j; hash}.values
["a"]
特别是对于大数组,这应该会更快,因为我们不需要每次使用include?来搜索数组。
干杯...
class EqualityWrapper
attr_reader :obj
def initialize(obj, eq, hash)
@obj = obj
@eq = eq
@hash = hash
end
def ==(other)
@eq[@obj, other.obj]
end
alias :eql? :==
def hash
@hash[@obj]
end
end
class Array
def uniq_by(eq, hash = lambda{|x| 0 })
map {|x| EqualityWrapper.new(x, eq, hash) }.
uniq.
map {|x| x.obj }
end
def uniq_ci
eq = lambda{|x, y| x.casecmp(y) == 0 }
hash = lambda{|x| x.downcase.hash }
uniq_by(eq, hash)
end
end
uniq_by
方法接受一个检查相等性的 lambda 函数和一个返回哈希值的 lambda 函数,并根据这些数据定义删除重复对象。
在此基础上实现的 uniq_ci
方法使用不区分大小写的比较方式删除字符串重复项。
["A", "a"].uniq(&:downcase)
。 - antinome