An addition to Array (or Enumerable)?

H

Harry Ohlsen

Yesterday, I wanted to get the output from "ls -l some_file" and pull out just the file size and the file name. As I start writing this, I realise, of course, that I'd have been better off just using the File#size method, but I still think the issue I hit is interesting.

I did something like:

listing = `ls -l #{path}`.split(/\s+/)

so I had the fields from "ls" as an array of strings.

What I then wanted to do was pull out items 4 and 8 (the size and filename) into a new two-element array. I half expected to be able to do that via:

data = listing[[4, 8]]

but that doesn't work.

Someone will probably tell me there's an easy way to achieve this. Please feel free to do so.

However, I think it would be nice if the indexing operator for Array, and maybe Hash, or perhaps anything Enumerable, would accept an array as parameter and return another array containing the corresponding items, to allow for non-contiguous selections.

I haven't really thought it through in the case of hashes. Perhaps in that case, one would want to get back a new hash, although I can't imagine that.

Anyway, just a thought.

Cheers,

Harry O.
 
G

Gennady

Yesterday, I wanted to get the output from "ls -l some_file" and pull
out just the file size and the file name. As I start writing this, I
realise, of course, that I'd have been better off just using the
File#size method, but I still think the issue I hit is interesting.

I did something like:

listing = `ls -l #{path}`.split(/\s+/)

listing = `ls -l #{path}`.split
is enough.
so I had the fields from "ls" as an array of strings.

What I then wanted to do was pull out items 4 and 8 (the size and
filename) into a new two-element array. I half expected to be able to
do that via:

data = listing[[4, 8]]

data = listing.select(4,8)
or for older Ruby
data = listing.indices(4,8)

If you want to extract a file name, I would use index -1 instead of 8
to get the last element. "ls -l" produces more fields for device nodes
(in this case index 4 refers to the major device number followed by a
comma).
but that doesn't work.

Someone will probably tell me there's an easy way to achieve this.
Please feel free to do so.

However, I think it would be nice if the indexing operator for Array,
and maybe Hash, or perhaps anything Enumerable, would accept an array
as parameter and return another array containing the corresponding
items, to allow for non-contiguous selections.

I haven't really thought it through in the case of hashes. Perhaps in
that case, one would want to get back a new hash, although I can't
imagine that.

Anyway, just a thought.

Cheers,

Harry O.

Sincerely,
Gennady Bystritsky
 
T

Tim Hunter

What I then wanted to do was pull out items 4 and 8 (the size and
filename) into a new two-element array. I half expected to be able to do
that via:

data = listing[[4, 8]]

but that doesn't work.
irb(main):001:0> x = ['A','B','C','D'] => ["A", "B", "C", "D"]
irb(main):002:0> y = x[0],x[1]
=> ["A", "B"]
irb(main):003:0> p y
["A", "B"]
=> nil
 
G

Gennady

Yesterday, I wanted to get the output from "ls -l some_file" and pull
out just the file size and the file name. As I start writing this, I
realise, of course, that I'd have been better off just using the
File#size method, but I still think the issue I hit is interesting.

I did something like:

listing = `ls -l #{path}`.split(/\s+/)

listing = `ls -l #{path}`.split
is enough.
so I had the fields from "ls" as an array of strings.

What I then wanted to do was pull out items 4 and 8 (the size and
filename) into a new two-element array. I half expected to be able to
do that via:

data = listing[[4, 8]]

data = listing.select(4,8)

Oops, just checked that in final Ruby 1.8.1 it should be
data = listing.values_at(4,8)

Strange, ri 1.8b claims that Array#select([anIndex]*) may be used,
however I got this error:
irb(main):001:0> [1,2].select(1)
ArgumentError: wrong number arguments (1 for 0)
from (irb):1:in `select'
from (irb):1
irb(main):002:0> VERSION
=> "1.8.1"

or for older Ruby
data = listing.indices(4,8)

If you want to extract a file name, I would use index -1 instead of 8
to get the last element. "ls -l" produces more fields for device nodes
(in this case index 4 refers to the major device number followed by a
comma).


Sincerely,
Gennady Bystritsky

Sincerely,
Gennady Bystritsky
 
G

Gavin Sinclair

[Gennady:]
What I then wanted to do was pull out items 4 and 8 (the size and
filename) into a new two-element array. I half expected to be able to
do that via:

data = listing[[4, 8]]

data = listing.select(4,8)
or for older Ruby
data = listing.indices(4,8)

Enumerable#select is an alias for #find_all.

#values_at is the 1.8 version of #indices (I miss that method name :).

Gavin
 
H

Harry Ohlsen

Gennady said:
data = listing.values_at(4,8)

Thanks!

Obviously, I should have tried

puts [].methods.sort.join("\n")

in irb, to see what methods are currently available for arrays. I'm pretty sure I would have guessed that values_at was what I was looking for!

Sadly, I just use ri (and rj) and neither of them listed values_at. Somehow, I didn't notice Array#select in either of them; either that or I misread the documentation.

Note: I still think that indexing an array with an array of indices is such an obvious thing to try that it should be there, but for the time being, I'll just spend some time reading through the updated documentation once the new ri comes out.

Cheers,

Harry O.
 
H

Harry Ohlsen

Tim said:
irb(main):001:0> x = ['A','B','C','D'] => ["A", "B", "C", "D"]
irb(main):002:0> y = x[0],x[1]
=> ["A", "B"]
irb(main):003:0> p y
["A", "B"]

Sure, that would work.

Of course, it doesn't look so neat when the name of the array is more than one character, and the list of indices is longer.

It feels just a little repetitious (again, not for a couple of indices). It could also be messy if the set of indices you wanted was in a variable, rather than hard-coded as in the specific case I gave as an example.

At this point, it's an academic exercise. As I said in my original post, in my real-world case, I really should have just used File#size to get what I wanted, but it's so much harder to code after a couple of bottles of Christmas cheer :).

H.
 
G

Gavin Sinclair

Gennady said:
data = listing.values_at(4,8)

Thanks!

Obviously, I should have tried

puts [].methods.sort.join("\n")

The "join" method is redundant unless you have modified the output
separator :)
Sadly, I just use ri (and rj) and neither of them listed values_at.
Somehow, I didn't notice Array#select in either of them; either that or
I misread the documentation.

I'm pretty sure that ri 1.8b contains values_at. I'm surprised about rj,
since I thought it was based on 1.8b. Anyway, rj is becoming blissfully
redundant as Dave improves ri. The pace of that improvement is
astonishing (see recent Ruby ChangeLog entries).

Anyway, you may want to check rdoc.sf.net to see if your 'ri' is up to
date with the latest stable release (not the new experimental stuff).
Note: I still think that indexing an array with an array of indices is
such an obvious thing to try that it should be there, but for the time
being, I'll just spend some time reading through the updated
documentation once the new ri comes out.

Not in my opinion, actually. It makes sense once I see it, but the code
you presented is unappealing to me: too many [[ and ]] :). But if that's
what I'd seen first in Ruby, I probably wouldn't have thought twice.

Cheers,
Gavin
 
D

Dave Thomas

Strange, ri 1.8b claims that Array#select([anIndex]*) may be used,
however I got this error:

It changed... :)

The new ri has it right:


dave[ruby/ruby 17:06:31] ri -f bs Array.select
----------------------------------------------------------- Array#select
array.select {|i| block } -> an_array
------------------------------------------------------------------------
Invokes the block passing in successive elements from arr,
returning an array containing those elements for which the block
returns a true value (equivalent to Enumerable#select).

a = %w{ a b c d e f }
a.select(1, 3, 5) #=> ["b", "d", "f"]
a.select(1, 3, 5, 7) #=> ["b", "d", "f", nil]
a.select(-1, -3, -5, -7) #=> ["f", "d", "b", nil]
a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"]


Cheers

Dave
 
H

Harry Ohlsen

Gavin said:
Obviously, I should have tried

puts [].methods.sort.join("\n")


The "join" method is redundant unless you have modified the output
separator :)

Thanks.

That's the only problem with POLS ... when I try something and it just works (as it so often does), I keep that idiom in my head forever, when there's almost always a simpler way :).

I think the only solution is to try to read more of other people's Ruby code, in which case I'd notice things like that and think "I wonder why they don't have join("\n") there?".
I'm pretty sure that ri 1.8b contains values_at. I'm surprised about rj,
since I thought it was based on 1.8b. Anyway, rj is becoming blissfully
redundant as Dave improves ri. The pace of that improvement is
astonishing (see recent Ruby ChangeLog entries).

I downloaded the latest rj from CVS just recently, but that's at home. I'll make sure to check when I get a chance. Maybe it's there and I was just more sheets to the wind than I remember!
Anyway, you may want to check rdoc.sf.net to see if your 'ri' is up to
date with the latest stable release (not the new experimental stuff).

Sadly, the web site is down for maintenance. I'll check back sometime soon, though.
Note: I still think that indexing an array with an array of indices is
such an obvious thing to try that it should be there, ...


Not in my opinion, actually. It makes sense once I see it, but the code
you presented is unappealing to me: too many [[ and ]] :). But if that's
what I'd seen first in Ruby, I probably wouldn't have thought twice.

I guess that's similar to my previous comment about remembering the first thing you see that works ... perhaps this is just a further analogue of duck typing ... imprinting :).

Cheers,

H.
 
T

Thomas Uehlinger

Strange, ri 1.8b claims that Array#select([anIndex]*) may be used,
however I got this error:

It changed... :)

The new ri has it right:


dave[ruby/ruby 17:06:31] ri -f bs Array.select
----------------------------------------------------------- Array#select
array.select {|i| block } -> an_array

The text is ok.
a = %w{ a b c d e f }
a.select(1, 3, 5) #=> ["b", "d", "f"]
a.select(1, 3, 5, 7) #=> ["b", "d", "f", nil]
a.select(-1, -3, -5, -7) #=> ["f", "d", "b", nil]

But these examples don't work in 1.9.0
a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"]

This one is ok again.

-- Thomas Uehlinger
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,481
Members
44,900
Latest member
Nell636132

Latest Threads

Top