2010-03-25 35 views
10

紅寶石1.8.6刪除Ruby數組中的相鄰元素?

我有一個包含數值的數組。我想要減少它,以便將相同值的序列簡化爲該值的單個實例。

所以我想

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

,以減少

[1, 2, 3, 2, 3] 

正如你所看到的,Array#uniq不會在這種情況下工作。

我有以下的,其工作原理:

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

任何人都可以拿出更少的醜陋的東西嗎?

回答

19

對於最簡單的,最瘦的解決方案,你可以使用的方法Enumerable#chunk

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

它是用Ruby 1.9.2介紹。如果您不幸使用較舊的紅寶石,您可以使用我的backports寶石和require 'backports/1.9.2/enumerable/chunk'

+0

我剛試過這個 - 非常好。謝謝! – 2010-03-25 16:31:54

+1

你不需要x.first,你可以簡單地說。地圖(&:first) – Darkmouse 2014-11-06 03:20:53

+0

@DarkMouse實際上你在1.8.6中實現了:-)。這與4年前相關,但今天並不多。我已經更新了我的回答 – 2014-11-06 16:20:36

0

我只能想到這個

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

但或多或少相同。

1

除非你是非常關心速度塊將計算的,我建議你只是這一行添加到您的塊的末尾,以獲得所需的輸出:

a.compact! 

這將只刪除所有你介紹給陣列早些時候nil元素(想成爲一式兩份),形成所需輸出:[1, 2, 3, 2, 3]

如果想要另一個算法,這裏是東西遠醜陋比你的。 :-)

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 

給你的輸出:

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

在我看來,你的代碼是好的。只需添加a.compact!電話,並對您進行排序。

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

我也記得'#inject'。它肯定比我發佈的嘗試更清晰,而且它更多地是「Rubyish」。 '#chunk'的東西很難打敗,儘管... – 2010-03-25 15:15:51

1

另一種解決方案:

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

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

我似乎忘記了'require'enumerator',這往往是一個錯誤。我敢打賭,我可以在我的代碼中找到十幾個我應該使用'#each_cons'的地方。謝謝! – 2010-03-26 08:37:18

1

如果數字都是個位數0-9:a.join.squeeze('0-9').each_char.to_a應該工作。

+0

在我的情況下,他們不是,但你給我的方法,如果我猴子補丁的名稱:'陣列#擠壓' – 2010-03-28 12:50:58