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,

···

--
http://twitter.com/bil_kleb
http://fun3d.larc.nasa.gov

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

···

2009/7/2 Bil Kleb <Bil.Kleb@nasa.gov>:

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?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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 Gray II

···

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

Hi --

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?

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

···

On Thu, 2 Jul 2009, Bil Kleb wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

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

James Edward Gray II

···

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

2009/7/2 Bil Kleb <Bil.Kleb@nasa.gov>:

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?

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"]

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.

···

--
http://twitter.com/bil_kleb

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

···

2009/7/2 James Gray <james@grayproductions.net>:

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme 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,

···

--
http://twitter.com/bil_kleb

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

···

On 02.07.2009 20:33, Bil Kleb wrote:

Robert Klemme 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.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Robert Klemme wrote:

···

On 02.07.2009 20:33, Bil Kleb 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,
--
http://twitter.com/bil_kleb