2009-07-09 6 views

Trả lời

16

Chỉ cần làm cho trường hợp nhất quán trước.

ví dụ:

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

Edit: Nếu như mikej cho thấy, các yếu tố hoàn trả phải được chính xác giống như trong mảng ban đầu, sau đó điều này sẽ làm điều đó cho bạn:

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

Chỉnh sửa2 Giải pháp cần thỏa mãn mikej :-)

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

Trong khi điều này có thể làm việc cho các ví dụ đưa ra nếu danh sách là một cái gì đó như ["Hello", "HELLO"] sau đó ["Hello", "HELLO"]. Bản đồ {| i | i.downcase} .uniq sẽ trả về ["hello"] không khớp với một trong hai chuỗi trong danh sách gốc. – mikej

+0

Giải pháp đã chỉnh sửa là tốt, ngoại trừ việc nó sẽ xây dựng danh sách downcased bằng cách sử dụng result.map {| i | i.downcase} nhiều lần (một lần cho mỗi phần tử trong danh sách ban đầu) vì vậy có thể thực hiện một lần như một câu lệnh riêng biệt và lưu trữ trong một biến tạm thời nếu danh sách lớn. – mikej

+1

Giải pháp @Eric C đơn giản hơn rất nhiều. – depquid

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

hoặc

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

Ack! Bị đánh vào nó! – Codebeef

0

Một giải pháp tổng quát hơn (mặc dù không phải là hiệu quả nhất):

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 

Phương pháp uniq_by mất một lambda để kiểm tra sự bình đẳng, và một lambda mà trả về một băm và loại bỏ các đối tượng trùng lặp như được xác định bởi các dữ liệu đó.

Thực hiện trên hết, phương pháp uniq_ci loại bỏ các chuỗi trùng lặp bằng cách sử dụng so sánh phân biệt chữ hoa chữ thường.

7

bạn có thể tạo bản đồ (Hash) giữa trường hợp được chuẩn hóa (ví dụ:downcased) giá trị và giá trị thực tế và sau đó chỉ mất các giá trị từ các hash:

["a", "b", "A", "C"]\ 
.inject(Hash.new){ |h,element| h[element.downcase] = element ; h }\ 
.values 

chọn xuất hiện cuối cùng của một từ nhất định (case insensitive):

["A", "b", "C"] 

nếu bạn muốn xuất hiện đầu tiên :

["a", "b", "A", "C"]\ 
.inject(Hash.new){ |h,element| h[element.downcase] = element unless h[element.downcase] ; h }\ 
.values 
+0

+1 Rất thông minh. – DanSingerman

2

Một chút hiệu quả hơn và cách là sử dụng các phím uniq trong băm, vì vậy kiểm tra này:

["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] = j; hash}.values 

sẽ trở lại yếu tố cuối cùng, trong trường hợp này

["A"] 

trong khi sử dụng || = như assign điều hành:

["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] ||= j; hash}.values 

sẽ trở lại phần tử đầu tiên, trong trường hợp này

["a"] 

đặc biệt đối với các mảng lớn, điều này sẽ nhanh hơn chúng tôi không tìm kiếm mảng mỗi lần sử dụng bao gồm?

cổ vũ ...

3

Nếu bạn đang sử dụng ActiveSupport, bạn có thể sử dụng uniq_by. Nó không ảnh hưởng đến trường hợp của đầu ra cuối cùng.

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

Có một cách khác để bạn có thể thực hiện việc này. Bạn thực sự có thể chuyển một khối đến uniq hoặc uniq! có thể được sử dụng để đánh giá từng phần tử.

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

hoặc

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

Trong trường hợp này, mặc dù tất cả mọi thứ sẽ là trường hợp nhạy cảm vì vậy nó sẽ luôn luôn trở về mảng ["A"]

+6

Câu trả lời hay. Lưu ý rằng biến thể hơi ngắn hơn là '[" A "," a "]. Uniq (&: downcase)'. – antinome

+0

@antinome Dễ đọc hơn nhiều. –

+0

Điều này rõ ràng nên là câu trả lời được chấp nhận ... –