2015-05-12 199 views
4

我試圖找到相當於remove_range(當然不存在)的東西,如下所示。似乎沒有簡單的方法來實現此功能。如何從陣列中刪除範圍

a = [0,2,8,2,4,5,] 
b = a.remove_range(1,2) #remove items between index 1 and 2 ,inclusively 
#expect b == [0,2,4,5] 
b = a.remove_range(3,4) 
#expect b == [0,2,8,5] 

發佈您的解決方案:)

假設範圍的大小爲M,之前,請至少測試上述兩種情況下,這種操作應該需要O(1)空間和O(NM)時間複雜。

編輯: 我看到人們不斷髮布a - a[range]。但它是不正確的,那就是刪除[範圍]中存在的元素,而不是去除屬於範圍的元素。

a - a[1..2]將返回[0, 4, 5]。但是,我們想保留第三個元素,即2

+0

是一個Ruby API /語法問題或編碼/算法問題? – coderz

+0

+ coderz都:) – pierrotlefou

+0

我不同意它「不存在」。它只是沒有命名你認爲它是。 –

回答

3

你可以做的可枚舉模塊的一些很酷的技巧:

a = [0, 2, 8, 2, 4, 5] 
r = 1..2 
a.reject.with_index { |v, i| r.include?(i) } # => [0, 2, 4, 5] 

請注意,這不會修改原始數組,但會返回一個新數組。如果要修改陣列,可以使用reject!

+0

這很棘手,我不知道'.reject.with_index'的東西。酷一個。 – pierrotlefou

+2

我聽到有人說:「爲什麼沒有格雷森使用[Range#cover](http://ruby-doc.org/core-2.2.0/Range.html#method-i-include-3F)?而不是[Range#include](http://ruby-doc.org/core-2.2.0/Range.html#method-i-include-3F)?,它檢查範圍內的每個元素?「。啊,但是'include?'足夠聰明地知道,就像'cover?'一樣,當它們是數字時,它可以使用端點。 –

+0

@CarySwoveland謝謝你指出。 – pierrotlefou

1

這是內置到數組類中的。只是減去你不想要的部分:

2.0.0-p353 :001 > ar = [0,2,8,2,4,5] 
=> [0, 2, 8, 2, 4, 5] 
2.0.0-p353 :002 > ar - ar[2..3] 
=> [0, 4, 5] 
0
a = [0,2,8,2,4,5]  
j = 1 

(3..4).each do |i| 
    j == 1 ? a.delete_at(i) : a.delete_at(i-1) 
    j += 1 
end 

b = a 
[0, 2, 8, 5] 
+0

它不會'工作。嘗試刪除(3..4)中的元素。 – pierrotlefou

+0

'delete_at'操作是O(n)時間複雜度(請參閱http://stackoverflow.com/questions/28510123/ruby-delete-a-value-from-sorted-unique-array-at-olog-n-runtime) ,違反時間複雜性要求。 – coderz

+1

如果您希望刪除元素,則必須多次刪除同一索引,或者通過索引從最高索引刪除索引。請注意,變異數組。 –

1
class Array 
    def remove_range(sp, ep) 
    raise ArgumentError if sp < 0 || ep > size - 1 
    slice(0...sp).concat(slice(ep+1..-1)) 
    end 
end 

感謝卡里Swoveland對他善意的提醒

+1

您可能希望引發'ArgumentError'異常,而不是返回'false'。其餘的可以表達爲'slice(0 ... sp).concat(slice(ep + 1 ..- 1))'。 'Array#concat'比'+'更有效,因爲它避免了創建兩個臨時數組。 –

+0

@CarySwoveland,你是對的。 – ShallmentMo

+0

一個小問題:當'if'語句在'if'和'end'之間只有一行時,有些人更喜歡寫(例如):'如果sp_size-1'則引發ArgumentError。 –

1
class Array 
    def remove_range(f,l) 
    self[0..f-1].concat(self[l+1..-1]) 
    end 
end 

a = [0,2,8,2,4,5] 
b = a.remove_range(1,2) 
[0, 2, 4, 5] 
c = a.remove_range(3,4) 
[0, 2, 8, 5] 
+0

是的,我認爲這是最直接的(不是最酷的)方式:) – pierrotlefou

+0

@pierr儘管如此,除非你的數組總是很短,否則請小心'+'。 –

+0

@DaveNewton是的,它可以工作,但表現不是很好。 – pierrotlefou

1
# Use: array.slice!(range) 
a = [0,2,8,2,4,5,] 

a.slice!(1..2) 
a # => [0, 2, 4, 5] 

或爲指數範圍爲3〜4

a.slice!(3..4) 
a # => [0, 2, 8, 5] 
0

嘗試時髦的東西與字符串操作。我認爲這是O(4 * M),但如果那甚至是一件事!

a.join.gsub(/#{a.join[1..2]}/,'').split('').map{|i| i.to_i} 
=> [0, 2, 4, 5] 
a.join.gsub(/#{a.join[3..4]}/,'').split('').map{|i| i.to_i} 
=> [0, 2, 8, 5]