Forum: Ruby delete_if_with_index or delete_at(array) in 1.8.6?

Posted by Bil Kleb (Guest)
on 2009-07-02 14:21
(Received via mailing list)
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,
Posted by Robert Klemme (Guest)
on 2009-07-02 14:46
(Received via mailing list)
2009/7/2 Bil Kleb <Bil.Kleb@nasa.gov>:
>
>
>  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
Posted by James Gray (bbazzarrakk)
on 2009-07-02 14:48
(Received via mailing list)
On Jul 2, 2009, at 7:45 AM, Robert Klemme 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.  ;)

James Edward Gray II
Posted by James Gray (bbazzarrakk)
on 2009-07-02 14:52
(Received via mailing list)
On Jul 2, 2009, at 7:20 AM, Bil Kleb 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 Gray II
Posted by David A. Black (Guest)
on 2009-07-02 14:55
(Received via mailing list)
Hi --

On Thu, 2 Jul 2009, Bil Kleb 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
Posted by Robert Klemme (Guest)
on 2009-07-02 16:38
(Received via mailing list)
2009/7/2 James Gray <james@grayproductions.net>:

> You need to reread what Bil was asking for.  ;)

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. :-)

Kind regards

robert
Posted by Bil Kleb (Guest)
on 2009-07-02 20:35
(Received via mailing list)
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.
Posted by Bil Kleb (Guest)
on 2009-07-02 20:36
(Received via mailing list)
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,
Posted by Robert Klemme (Guest)
on 2009-07-02 22:50
(Received via mailing list)
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.

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

:-)

Kind regards

  robert
Posted by Bil Kleb (Guest)
on 2009-07-02 23:55
(Received via mailing list)
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,
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.