2015-05-12 3 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) время сложность.

EDIT: Я вижу, что люди продолжают размещать a - a[range]. Но это неверно, т. Е. Удалить элементы в [range], а не удалять элемент, принадлежащий диапазону.

a - a[1..2] вернет [0, 4, 5]. Однако мы хотим сохранить 3-й элемент, который равен 2.

+0

Является ли Ruby API/грамматическим вопросом или вопросом кодирования/алгоритма? – coderz

+0

+ coderz both :) – 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 

Спасибо Cary Swoveland за хорошую посоветуйте

+1

Возможно, вы захотите поднять исключение 'ArgumentError', а не возвращать' false'. Остальное можно было бы альтернативно выразить «slice (0 ... sp) .concat (slice (ep + 1 ..-1))». 'Array # concat' более эффективен, чем' + ', потому что он избегает создания двух временных массивов. –

+0

@CarySwoveland, вы правы. – ShallmentMo

+0

Небольшая точка: когда оператор 'if' имеет только одну строку между' if' и 'end', некоторые предпочитают писать (например):' raise ArgumentError, если sp < 0 || ep > размер - 1'. –

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] 
Смежные вопросы