A simple newbie question (arrays and strings)

K

koichirose

Today I started programming in ruby.
Here's what I managed to do so far:

string = Dir.entries(".")
string.delete_at(0)
string.delete_at(0)

1. I get a list of files
2-3. I delete the first two elements ('.' and '..')

Now my files are all like "something - some other thing"
I want to split them:

string.each do |s|
puts s.split("-")[0]
end

So it outputs the "something" part in my filenames.
Now I'd like to remove duplicate entries (.uniq method right?).
Can it be done in a single line? If not, how do i get an array
containing only the "something" part to work on with .uniq?

I tried with some loops, to create a new array with the splitted string
in it, but my PHP approach doesn't work:
i = 0
for i in string
splitted = i.split("-")[0]
i += 1
end

Thank you!
 
S

Stefano Crocco

Today I started programming in ruby.
Here's what I managed to do so far:

string = Dir.entries(".")
string.delete_at(0)
string.delete_at(0)

1. I get a list of files
2-3. I delete the first two elements ('.' and '..')

Now my files are all like "something - some other thing"
I want to split them:

string.each do |s|
puts s.split("-")[0]
end

So it outputs the "something" part in my filenames.
Now I'd like to remove duplicate entries (.uniq method right?).
Can it be done in a single line? If not, how do i get an array
containing only the "something" part to work on with .uniq?

I tried with some loops, to create a new array with the splitted string
in it, but my PHP approach doesn't work:
i = 0
for i in string
splitted = i.split("-")[0]
i += 1
end

Thank you!


If I understand you correctly, this (untested) should do what you want:
Dir.entries('.')[2..-1].map{|f| f.split('-')[0]}.uniq

Dir.entries('.')[2..-1]

returns an array containing all the contents of the current directory except
the first two entries (actually, the [] method of an array, when called with a
range returns all the elements of the array from the first index to the last.
Since negative indexes count from right to left, with the rigthmost element
having index -1, here you get all the entries from 2 to the last). This avoids
the two calls to delete_at.

Then map is called on the array with the names of the files. Array#map passes
each element of the array to the block and returns an array containing the
values returned by the block for each element. In this case, each element is a
string of the form 'something-something_else'. The block splits the name of
the file on the '-' character, then takes (and implicitly returns) the first
half (thanks to the [0]). This means that map returns an array containing all
the first parts of the file names (the ones you want).

After that, we call uniq on the array, creating a new array without
duplicates.

I hope this helps

Stefano
 
Y

yermej

Today I started programming in ruby.
Here's what I managed to do so far:

string = Dir.entries(".")
string.delete_at(0)
string.delete_at(0)

1. I get a list of files
2-3. I delete the first two elements ('.' and '..')

Now my files are all like "something - some other thing"
I want to split them:

string.each do |s|
puts s.split("-")[0]
end

So it outputs the "something" part in my filenames.
Now I'd like to remove duplicate entries (.uniq method right?).
Can it be done in a single line? If not, how do i get an array
containing only the "something" part to work on with .uniq?

I tried with some loops, to create a new array with the splitted string
in it, but my PHP approach doesn't work:
i = 0
for i in string
splitted = i.split("-")[0]
i += 1
end

Thank you!


One way would be to use Dir.glob:

unique_array = Dir.glob('*-*').map {|f| f.split('-')[0]}.uniq

Then you only get filenames that have - in them.

Or:

unique_array = Dir.entries('.')[2..-1].map {|f| f.split('-')[0]}.uniq

But starting from here:
string = Dir.entries(".")
string.delete_at(0)
string.delete_at(0)
string.map! {|f| f.split('-')[0]}.uniq!
 
K

koichirose

Stefano said:
If I understand you correctly, this (untested) should do what you want:
Dir.entries('.')[2..-1].map{|f| f.split('-')[0]}.uniq

Hai capito bene :) Continuo in inglese che penso sia contro le regole
parlare in italiano ^^
Dir.entries('.')[2..-1] This avoids
the two calls to delete_at.

Nice :)
This means that map returns an array containing all
the first parts of the file names (the ones you want).

Does map{} work as some sort of loop in which it executes the split
method on each element?
I hope this helps

It works! I see that .uniq is case-sensitive (something else !=
something Else). Can I avoid that?
Grazie!
 
K

koichirose

yermej said:
unique_array = Dir.entries('.')[2..-1].map {|f| f.split('-')[0]}.uniq
string.map! {|f| f.split('-')[0]}.uniq!

What if I do:
Dir.entries('.')[2..-1].map! {|f| f.split('-')[0]}.uniq

with map! instead of map ?
I'd now have Dir.entries trimmed, splitted and "uniqed" ?
Thanks
 
S

Simon Krahnke

* koichirose said:
yermej said:
unique_array = Dir.entries('.')[2..-1].map {|f| f.split('-')[0]}.uniq
string.map! {|f| f.split('-')[0]}.uniq!

What if I do:
Dir.entries('.')[2..-1].map! {|f| f.split('-')[0]}.uniq

with map! instead of map ?

map! changes the array it's called on. since that is a temporary array
returned by Dir.entries[2..-1] which is discarded after map! that won't
work.

mfg, simon .... l
 
S

Simon Krahnke

* koichirose said:
It works! I see that .uniq is case-sensitive (something else !=
something Else). Can I avoid that?

Yes, just convert it to lower case before the uniq:

Dir.entries('.')[2..-1].map{|f| f.split('-')[0].lower}.uniq

mfg, simon .... l
 
K

koichirose

Simon said:
map! changes the array it's called on. since that is a temporary array
returned by Dir.entries[2..-1] which is discarded after map! that won't
work.

Right..Thank you!
 
K

koichirose

koichirose said:
Yes, .downcase, confirmed

I have a problem, why does this work:
list = Dir.entries('.')[2..-1].map{|f| f.split(' - ')[0].capitalize}

And this doesn't?
list2 = Dir.entries('.')[2..-1].map{|f| f.split(' - ')[1].capitalize}

It returns: hello.rb:7: undefined method `capitalize' for nil:NilClass
(NoMethodError)
from hello.rb:7:in `map'

Thank you
 
D

Dave Bass

koichirose said:
It returns: hello.rb:7: undefined method `capitalize' for nil:NilClass
(NoMethodError)

That error message means you're trying to call the capitalize method on
something that doesn't exist. I.e. xxx.capitalise where xxx evaluates to
nil. The class NilClass doesn't have a capitalize method. Your problem
is with xxx; trying "p"-ing it.
 
K

koichirose

Dave said:
That error message means you're trying to call the capitalize method on
something that doesn't exist. I.e. xxx.capitalise where xxx evaluates to
nil. The class NilClass doesn't have a capitalize method. Your problem
is with xxx; trying "p"-ing it.


Ok, but those 2 lines are the same, except that with list2 I take the
part after ' - '.
If I do:

#~ j=0
#~ for i in list2
#~ puts list2[j]
#~ j +=1
#~ end

it works. Why are list and list2 behaving differently?
 
T

Todd Benson

Dave Bass wrote:
Ok, but those 2 lines are the same, except that with list2 I take the part
after ' - '.
If I do:

#~ j=0
#~ for i in list2
#~ puts list2[j]
#~ j +=1
#~ end

You have entries that either have no dash "-", or have one but nothing
after. You can NilClass#puts, but not just any method on it, such as
#capitalize. If you don't need them (like, for example, counting
purposes), remove your nils out of the array list with #compact.
Example in irb...

[1, nil, 2].compact
=> [1, 2]

Todd
 

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,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top