2012-03-07 44 views
6

Nói rằng tôi có một mảng mà trông giống như:Làm cách nào để phát hiện các giá trị trùng lặp trong một mảng trong Ruby?

a = [cat, dog, cat, mouse, rat, dog, cat] 

Làm thế nào để chu kỳ thông qua đó, và làm điều gì đó với bản sao - ví dụ nói xóa chúng?

Nói cách khác, nếu tôi đã thực hiện a.each do |i|, làm cách nào để đánh giá [0], so với [1], [2], a [3] ... và sau đó khi tôi tìm thấy thứ tôi muốn, nói một [2] trong trường hợp này có bản sao đầu tiên, sau đó đẩy nó vào một ngăn xếp hoặc loại bỏ nó hoặc một cái gì đó.

Tôi biết cách đánh giá khóa, so với giá trị ... nhưng làm cách nào để đánh giá các giá trị với nhau trong cùng một mảng?

Cảm ơn.

Trả lời

11

Bạn có thể tạo một hash để lưu trữ số lần bất kỳ yếu tố được lặp lại. Vì vậy, lặp qua mảng chỉ một lần.

h = Hash.new(0) 
['a','b','b','c'].each{ |e| h[e] += 1 } 

nên dẫn

{"a"=>1, "b"=>2, "c"=>1} 
+1

Tại sao không 'h = Hash.new (0)' và 'h [e] + = 1'? –

+0

Vấn đề cú pháp. Đó là lúc các lập trình viên tùy ý. – ch4nd4n

+0

Điều này thực sự là những gì tôi đã cố gắng để làm .... nhưng ... Tôi không thể tìm ra cách sử dụng 'nil?' Và phương thức tăng giống như thế này. Cảm ơn! – marcamillion

1

Một giải pháp đơn giản là chạy một vòng lặp kép:

a.each_with_index do |a1, idx1| 
    a.each_with_index do |a2, idx2| 
    next if idx1 >= idx2 # Don't compare element to itself 
         # and don't repeat comparisons already made 

    # do something with a pair of elements (a1, a2) 
    end 
end 

Nếu bạn chỉ muốn loại bỏ bản sao, có một phương pháp: Array#uniq.

+0

Nghĩ về điều này, nhưng có vẻ như rất lộn xộn. Có một giải pháp 'ruby-ish' tao nhã hơn? – marcamillion

+0

Để loại bỏ trùng lặp, có một phương pháp. Để so sánh tất cả các phần tử với nhau, có một vòng lặp đôi. Cá nhân tôi không thấy bất kỳ mớ hỗn độn nào trong đó. Đó là mã đơn giản mà đọc tốt. –

+0

Sergio phương pháp này không hiệu quả khi bạn đang so sánh không cần thiết đã được thực hiện trong quá khứ. Vòng lặp bên trong thứ hai của bạn sẽ bắt đầu lặp lại nó sau đó (tức là trong mảng) trên mỗi vòng lặp. – MMM

1

Sử dụng a.uniq! để xóa các từ khóa trùng lặp.

cũng thanh toán số ruby-doc.org nơi bạn có thể tìm thêm thông tin về các phương thức lớp của ruby.

+0

compact loại bỏ nils khỏi mảng. Làm thế nào là nó hữu ích trong tình huống này? –

+0

Đồng ý. Nhìn vào các tài liệu và nó không hoạt động. – marcamillion

+0

xin lỗi tôi cố gắng viết uniq. :) – lesce

3

Hãy thử điều này:

class Array 
    def find_dups 
     uniq.map {|v| (self - [v]).size < (self.size - 1) ? v : nil}.compact 
    end 
end 

a = ['cat', 'dog', 'cat', 'mouse', 'rat', 'dog', 'cat'] 

print a - a.find_dups # Removes duplicates 

find_dups sẽ trở lại các yếu tố đó có bản sao

5

này hoạt động một cách hiệu quả và khá đơn giản:

require 'set' 

visited = Set.new 
array.each do |element| 
    if visited.include?(element) 
    # duplicated item 
    else 
    # first appearance 
    visited << element 
    end 
end 
1

Hãy thử điều này:

 
array.inject({}){|h, e| h[e] = h[e].to_i + 1; h} 
0

này sẽ in tất cả các bản sao trong một mảng :

array.inject(Hash.new(0)) { |hash,val| 
    hash[val] += 1; 
    hash 
}.each_pair { |val,count| 
    puts "#{val} -> #{count}" if count > 1 
} 
0

Nếu bạn chỉ muốn loại bỏ các bản sao, điều dễ nhất cần làm là lấy mảng và làm mảng mảng &. Sử dụng toán tử &.

Nếu bạn muốn biết những gì lặp lại, chỉ cần so sánh mảng với mảng & mảng.

0

Nếu mảng có thể sắp xếp, thì một số thứ như dưới đây sẽ chỉ trả về các bản sao.

array.sort.each_cons(2).select {|p| p[0] == p[1] }.map &:first 

Sắp xếp mảng, sau đó ánh xạ nó thành các phần tử liên tiếp, chọn cặp giống nhau, ánh xạ tới phần tử.

0

Cách tốt nhất để làm điều đó là so sánh nó với phiên bản duy nhất của chính nó. Nếu nó giống nhau thì nó không có bản sao, nếu không thì các bản sao tồn tại.

unique_array = original_array.uniq 

có được một phiên bản duy nhất của mảng của bạn

if original_array == unique_array then return true else return false 

so sánh nó với mảng ban đầu của bạn.

Đơn giản!

Các vấn đề liên quan