2010-03-25 35 views
10

Ruby 1.8.6Xóa các phần tử giống nhau lân cận trong một mảng Ruby?

Tôi có một mảng chứa các giá trị số. Tôi muốn giảm nó sao cho các dãy của cùng một giá trị được giảm xuống một giá trị duy nhất của giá trị đó.

Vì vậy, tôi muốn

a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3] 

để giảm đến

[1, 2, 3, 2, 3] 

Như bạn thấy, Array#uniq sẽ không làm việc trong trường hợp này.

Tôi có những điều sau đây, trong đó hoạt động:

(a.size - 1).downto(1) { |i| a[i] = nil if a[i - 1] == a[i] } 

bất cứ ai có thể đến với cái gì ít xấu xí?

Trả lời

19

Đối với các giải pháp đơn giản nhất, nạc nhất, bạn có thể sử dụng phương pháp Enumerable#chunk:

a.chunk{|n| n}.map(&:first) 

Nó đã được giới thiệu trong Ruby 1.9.2. Nếu bạn không đủ may mắn để sử dụng những viên hồng ngọc cũ hơn, bạn có thể sử dụng đá quý backportsrequire 'backports/1.9.2/enumerable/chunk' của mình.

+0

Tôi vừa thử điều này - tuyệt vời. Cảm ơn! –

+1

Bạn không cần x.first, bạn chỉ cần nói.map (&: first) – Darkmouse

+0

@DarkMouse Bạn đã làm trong 1.8.6 :-) thực sự. Điều này có liên quan 4 năm trước, nhưng không nhiều ngày hôm nay. Tôi đã cập nhật câu trả lời của tôi –

0

tôi có thể nghĩ duy nhất của này

a.each_with_index{|item,i| a[i] = nil if a[i] == a[i+1] }.compact 

nhưng nó là nhiều hơn hoặc ít hơn như nhau.

1

Trừ khi bạn là rất liên quan với tốc độ khối đó sẽ tính toán tại, tôi sẽ đề nghị bạn chỉ cần thêm dòng này vào cuối khối của bạn để có được những kết quả mong muốn:

a.compact! 

Đó sẽ chỉ loại bỏ tất cả các yếu tố nil bạn giới thiệu với mảng trước đó (có tiện ích khác bản sao), tạo thành đầu ra mong muốn của bạn: [1, 2, 3, 2, 3]

Nếu bạn muốn thuật toán khác, đây là một cái gì đó xa uglier hơn của bạn. :-)

require "pp" 

a = [1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 2, 2, 3, 3, 3] 

i = 0 

while i < a.size do 
    e = a[i] 
    j = i 

    begin 
    j += 1 
    end while e == a[j] 

    for k in i+1..j-1 do 
    a[k] = nil 
    end 

    i = j 
end 

pp a 
a.compact! 
pp a 

Cung cấp cho bạn kết quả:

[1, nil, nil, 2, nil, 3, nil, nil, nil, 2, nil, nil, 3, nil, nil] 
[1, 2, 3, 2, 3] 

Theo tôi, mã của bạn là tốt. Chỉ cần thêm cuộc gọi a.compact! và bạn được sắp xếp.

5
a.inject([]){|acc,i| acc.last == i ? acc : acc << i } 
+0

Tôi cũng đã nhận được điều này, một khi tôi nhớ '# inject'. Nó chắc chắn là sạch hơn so với những nỗ lực tôi đăng và đó là rất nhiều "Rubyish". Điều '# chunk' khó đánh bại, mặc dù ... –

1

một giải pháp:

acc = [a[0]] 
a.each_cons(2) {|x,y| acc << y if x != y} 

hoặc

a.each_cons(2).inject([a[0]]) {|acc, (x,y)| x == y ? acc : acc << y} 
+0

Tôi dường như quên về 'yêu cầu' điều tra'', mà thường là một sai lầm. Tôi đặt cược tôi có thể tìm thấy một chục nơi trong mã của tôi, nơi tôi nên đã sử dụng '# each_cons'. Cảm ơn! –

1

Nếu những con số đều là một con số 0-9: a.join.squeeze('0-9').each_char.to_a nên làm việc.

+0

Trong trường hợp của tôi thì không, nhưng bạn đã cho tôi tên cho phương pháp nếu tôi vá lỗi: 'Array # squeeze' –

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