Delete_if_with_index or delete_at(array) in 1.8.6?

Hi,

Given an array of integers, I need to delete all those
entries that are lower than the current array index.

I first thought of the non-existent,

array.delete_if_with_index{ |e,i| e < i }

then,

remove_indices = []
array.each_with_index{ |e,i| remove_indices << i if e < i }
array.delete_at( remove_indices )

or the same, but with a fictious inject_with_index,

remove_indices = inject_with_index([]){|acc,e,i| acc << i if e < i }
array.delete_at( remove_indices )

and finally the 1.9 possibility,

array.map_with_index!{ |e,i| e < i ? nil : e }.compact!

before compromising with

array = (0…array.size).zip(array).map{ |i,e| e < i ? nil : e
}.compact

Anything more elegant available?

Or perhaps an alternative way to attack the problem?

Thanks,

2009/7/2 Bil K. [email protected]:

array.map_with_index!{ |e,i| e < i ? nil : e }.compact!

before compromising with

array = (0…array.size).zip(array).map{ |i,e| e < i ? nil : e }.compact

Anything more elegant available?

Or perhaps an alternative way to attack the problem?

irb(main):010:0> a = %w{foo bar baz}
=> [“foo”, “bar”, “baz”]
irb(main):011:0> current = 1
=> 1
irb(main):012:0> a.slice! 0…current
=> [“foo”]
irb(main):013:0> a
=> [“bar”, “baz”]

Kind regards

robert

On Jul 2, 2009, at 7:45 AM, Robert K. wrote:

then,
and finally the 1.9 possibility,
Or perhaps an alternative way to attack the problem?

irb(main):010:0> a = %w{foo bar baz}
=> [“foo”, “bar”, “baz”]
irb(main):011:0> current = 1
=> 1
irb(main):012:0> a.slice! 0…current
=> [“foo”]
irb(main):013:0> a
=> [“bar”, “baz”]

You need to reread what Bil was asking for. :wink:

James Edward G. II

On Jul 2, 2009, at 7:20 AM, Bil K. wrote:

Given an array of integers, I need to delete all those
entries that are lower than the current array index.

Anything more elegant available?

Or perhaps an alternative way to attack the problem?

On Ruby 1.9, your very first example can almost be made to work as is:

a = Array.new(10) { |i| i + [-1, 0, 1][rand(3)] }
=> [-1, 1, 2, 4, 3, 5, 7, 7, 9, 10]

a.delete_if.with_index { |e, i| e < i }
=> [1, 2, 4, 5, 7, 7, 9, 10]

James Edward G. II

Hi –

On Thu, 2 Jul 2009, Bil K. wrote:

array.map_with_index!{ |e,i| e < i ? nil : e }.compact!

before compromising with

array = (0…array.size).zip(array).map{ |i,e| e < i ? nil : e }.compact

Anything more elegant available?

Or perhaps an alternative way to attack the problem?

In 1.9 I would do:

a = [0,1,2,1,4,3,6,7,2]
=> [0, 1, 2, 1, 4, 3, 6, 7, 2]

a.reject!.with_index {|e,i| e < i }
=> [0, 1, 2, 4, 6, 7]

In 1.8 I’m not coming up with anything more elegant than:

a.values_at(*(0…a.size).reject {|i| a[i] < i })
=> [0, 1, 2, 4, 6, 7]

or some variant thereof.

David

2009/7/2 James G. [email protected]:

You need to reread what Bil was asking for. :wink:

Right. Now I got it. He means something like

irb(main):001:0> a = (1…10).map { rand(10) }
=> [8, 0, 4, 2, 1, 4, 5, 4, 2, 9]
irb(main):002:0> i = -1
=> -1
irb(main):003:0> a.delete_if {|x| i += 1; x < i}
=> [8, 4, 9]
irb(main):004:0>

Correct? Thanks for the heads up, James!

Site note: there seems to be a certain setting of the mind which
prevents that we consider a mutating operation in a “read only” block
used as filtering criterion. Yet we can do it. It took me a while,
too. :slight_smile:

Kind regards

robert

Robert K. wrote:

irb(main):002:0> i = -1
irb(main):003:0> a.delete_if {|x| i += 1; x < i}

Ah, if it weren’t for the two lines, I think I’d pick
this one.

Regards,

David A. Black wrote:

In 1.8 I’m not coming up with anything more elegant than:

a.values_at(*(0…a.size).reject {|i| a[i] < i })
=> [0, 1, 2, 4, 6, 7]

Nice.

Robert K. wrote:

On 02.07.2009 20:33, Bil K. wrote:

Ah, if it weren’t for the two lines, I think I’d pick
this one.

Even with two lines I personally find it more elegant than some of the
solutions you posted.

Mine we’re solutions, just dreams.

I liked David’s solution the best because I dislike initialization
separated from use (for some unknown-to-me reason).

Regards,

On 02.07.2009 20:33, Bil K. wrote:

Robert K. wrote:

irb(main):002:0> i = -1
irb(main):003:0> a.delete_if {|x| i += 1; x < i}

Ah, if it weren’t for the two lines, I think I’d pick
this one.

Even with two lines I personally find it more elegant than some of the
solutions you posted. I can even give you reasons:

  • it is straightforward and thus easy to understand
  • little code, despite the two lines
  • it does not create any temporary arrays of indexes or such which is
    the reason for:
  • it is probably pretty efficient
  • oh, and it should work on all versions of Ruby

:slight_smile:

Kind regards

robert