【问题标题】:How to uniq an array case insensitive如何使数组不区分大小写
【发布时间】:2009-07-09 11:39:56
【问题描述】:

据我所知,结果

["a", "A"].uniq 

["a", "A"]

我的问题是:

如何让 ["a", "A"].uniq 给我 ["a"] 或 ["A"]

【问题讨论】:

    标签: ruby arrays unique


    【解决方案1】:

    还有另一种方法可以做到这一点。您实际上可以将一个块传递给uniquniq!,用于评估每个元素。

    ["A", "a"].uniq { |elem| elem.downcase }  #=>  ["A"]
    

    ["A", "a"].uniq { |elem| elem.upcase }  #=>  ["A"]
    

    但在这种情况下,所有内容都将不区分大小写,因此它将始终返回数组 ["A"]

    【讨论】:

    • 很好的答案。请注意,稍短的变体是["A", "a"].uniq(&:downcase)
    • 此解决方案将优先使用第一个重复项,在本例中为 ["A"] 而不是 ["a"]。
    【解决方案2】:

    先让大小写一致。

    例如:

    ["a","A"].map{|i| i.downcase}.uniq
    

    编辑:如果按照 mikej 的建议,返回的元素必须与原始数组中的元素完全相同,那么这将为您完成:

    a.inject([]) { |result,h| result << h unless result.map{|i| i.downcase}.include?(h.downcase); result }
    

    Edit2 应该满足 mikej 的解决方案 :-)

    downcased = [] 
    a.inject([]) { |result,h| 
            unless downcased.include?(h.downcase);
                result << h
                downcased << h.downcase
            end;
            result}
    

    【讨论】:

    • 虽然这适用于给出的示例,如果列表类似于 ["Hello", "HELLO"] 然后 ["Hello", "HELLO"].map { |i| i.dow​​ncase }.uniq 将返回与原始列表中的任何一个字符串都不匹配的 ["hello"]。
    • 编辑的解决方案很好,除了它将使用 result.map{|i| 构建降级列表i.dow​​ncase} 多次(对于原始列表中的每个元素一次),因此可以将其作为单独的语句执行一次,如果列表很大,则存储在临时变量中。
    • @Eric C 的解决方案要简单得多。
    【解决方案3】:

    您可以在大小写规范化(例如降级)值和实际值之间建立映射(哈希),然后仅从哈希中获取值:

    ["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
    

    【讨论】:

      【解决方案4】:
      ["a", "A"].map{|x| x.downcase}.uniq
      => ["a"]
      

      ["a", "A"].map{|x| x.upcase}.uniq
      => ["A"]
      

      【讨论】:

        【解决方案5】:

        如果您使用 ActiveSupport,则可以使用 uniq_by。 不影响最终输出的大小写。

        ['A','a'].uniq_by(&:downcase) # => ['A']
        

        【讨论】:

          【解决方案6】:

          更有效的方法是在哈希中使用 uniq 键,所以检查一下:

          ["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?

          搜索数组

          干杯...

          【讨论】:

            【解决方案7】:

            更通用的解决方案(虽然不是最有效的):

            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 方法使用不区分大小写的比较删除重复的字符串。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-10-14
              • 1970-01-01
              • 2013-03-06
              • 2020-04-08
              • 1970-01-01
              • 1970-01-01
              • 2012-05-25
              • 2020-11-24
              相关资源
              最近更新 更多