2015-05-12 150 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]