Reinier
Reinier

Reputation: 215

How can I delete certain indeces defined in an array from an other array in ruby

I have a method that iterates over an array, does a bunch of stuff under certain conditions and depending on these conditions I would ALSO like to delete some of the elements. In order to keep track of the indexes I like to delete I converted the each in to an each_with_index loop and store the index of the elements that I like to delete in an array index_array. How can I delete exactly the items on those indexes in my original array? Looping over the index_array and using delete_at would change the original index. Please see below description of the scenario:

> my_array = [0,1,2,3,4,5,6,7]
> delete_these_indexes = [1,2,5]
the desired result is:
> my_array => [0,3,4,6,7,8]

Upvotes: 0

Views: 113

Answers (4)

user483040
user483040

Reputation:

Probably not the best answer, but you can do this as well:

delete_at_indices.each {|ind| my_array[ind] = nil }
my_array.delete(nil)

Takes a first pass to conceptually invalidate the data at the specified indices, then the call to .delete will blow out any values that match what's passed in.

This solution assumes that you can define a value that isn't valid for your array. Using nil will be problematic if you're treating this as a sparsely populated array (where nil is a valid value)

Technically you're iterating through each array once, but that Gentleman's Agreement on what your deletable value might make some people uncomfortable

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110665

keep_these_indexes = my_array.each_index.to_a - delete_these_indexes
  #=> [0, 3, 4, 6, 7]

If you wish to modify my_array (which appears to be the case):

my_array.replace(my_array.values_at(*keep_these_indexes))
  #=> [0, 3, 4, 6, 7]

If not:

new_array = my_array.values_at(*keep_these_indexes)

See Array#values_at.

Upvotes: 1

Jordan Running
Jordan Running

Reputation: 106027

How about this?

my_array = [0, 1, 2, 3, 4, 5, 6, 7]
delete_these_indices = [1, 2, 5]

delete_these_indices.sort.reverse_each {|i| my_array.delete_at(i) }

p my_array
# => [0, 3, 4, 6, 7, 8]

It's important to delete from the end of the array, since deleting an item will change the indices of all subsequent items, ergo sort.reverse_each. If you know the array is already sorted, you can just do reverse_each.

If you don't care bout modifying the delete_these_indices array, you can be somewhat more terse:

delete_these_indices.sort!
my_array.delete_at(i) while (i = delete_these_indices.pop)

Again, you can skip sort! if you know delete_these_indices is already sorted.

Upvotes: 3

larz
larz

Reputation: 5766

delete_these_indexes.each_with_index do |val, i|
    my_array.delete_at(val - i)
end

deletes at the desired index taking into account how many have previously been deleted and adjusting for that

https://repl.it/CeHZ

Upvotes: 0

Related Questions