Ruby noob with a coming from Python question

I am very new to ruby and thought I would start with my simplest python script and port it over and along the way, learn the "ruby way" of doing things. My solution so far is unsatisfactory and long. If you have any suggestions, most especially about the "ruby way" to write the file2Map method, I would appreciate it and all of my future ruby programs would also appreciate it.

Cheers,
Jeff Carlson

···

-------------------------------------------------------------
#!/usr/bin/python
# print statistics for seti@home jobs
from mx.DateTime import TimeDelta
import sys

# this method takes a file with key/value pairs, seperated by "="
# and makes a map of the file, keys and values, the length of the
# map is the length of the file
def getMapFromFile(fname):
  lines = open(fname).readlines()
         return dict([line.split("=") for line in lines])

# make maps of the two files
sMap = getMapFromFile(sys.argv[1])
uMap = getMapFromFile(sys.argv[2])

prog = float(sMap["prog"].strip())*100
et = TimeDelta(seconds=float(sMap["cpu"].strip()))

#print results
print '%.2f%c completed in %d:%02d:%02d' % (prog, '%', et.hour, /
  et.minute, et.second)
print 'units of work so far %s' % (uMap["nresults"].strip())

Oops, I meant the *getMapFromFile* function. If I could see the ruby way of writing a method to take a file of the form
key1=value1
key2=value2
etc
and easily make it into a hash in a concise way (as in the python example) that would be great.

Jeff Carlson wrote:

···

I am very new to ruby and thought I would start with my simplest python script and port it over and along the way, learn the "ruby way" of doing things. My solution so far is unsatisfactory and long. If you have any suggestions, most especially about the "ruby way" to write the file2Map method, I would appreciate it and all of my future ruby programs would also appreciate it.

Cheers,
Jeff Carlson

-------------------------------------------------------------
#!/usr/bin/python
# print statistics for seti@home jobs
from mx.DateTime import TimeDelta
import sys

# this method takes a file with key/value pairs, seperated by "="
# and makes a map of the file, keys and values, the length of the
# map is the length of the file
def getMapFromFile(fname):
    lines = open(fname).readlines()
        return dict([line.split("=") for line in lines])

# make maps of the two files
sMap = getMapFromFile(sys.argv[1])
uMap = getMapFromFile(sys.argv[2])

prog = float(sMap["prog"].strip())*100
et = TimeDelta(seconds=float(sMap["cpu"].strip()))

#print results
print '%.2f%c completed in %d:%02d:%02d' % (prog, '%', et.hour, /
    et.minute, et.second)
print 'units of work so far %s' % (uMap["nresults"].strip())

Jeff Carlson wrote:

I am very new to ruby and thought I would start with my simplest python script and port it over and along the way, learn the "ruby way" of doing things. My solution so far is unsatisfactory and long. If you have any suggestions, most especially about the "ruby way" to write the file2Map method, I would appreciate it and all of my future ruby programs would also appreciate it.

Cheers,
Jeff Carlson

-------------------------------------------------------------
#!/usr/bin/python
# print statistics for seti@home jobs
from mx.DateTime import TimeDelta
import sys

# this method takes a file with key/value pairs, seperated by "="
# and makes a map of the file, keys and values, the length of the
# map is the length of the file
def getMapFromFile(fname):
    lines = open(fname).readlines()
        return dict([line.split("=") for line in lines])

This should work:

def map_from(file)
   Hash[*File.readlines(file).map {|line| line.split '='}.flatten]
end

Broken down, File.readlines makes an Array of lines in the file; we
then #map it to split each line into the two parts and then #flatten
the Array from [[key1, val1], [key2, val2]] to [key1, val1, key2, val2].

This syntax can be used by Hash, so we just 'splat' the Array
to individual values by using the * operator.

# make maps of the two files
sMap = getMapFromFile(sys.argv[1])
uMap = getMapFromFile(sys.argv[2])

prog = float(sMap["prog"].strip())*100
et = TimeDelta(seconds=float(sMap["cpu"].strip()))

#print results
print '%.2f%c completed in %d:%02d:%02d' % (prog, '%', et.hour, /
    et.minute, et.second)
print 'units of work so far %s' % (uMap["nresults"].strip())

E

results = File.open(file_name) do |file|
       file.map { |line|
             line.chomp.split(/=/)[0..1]
       }
end.inject({}) { |results, (key, val)| results[key] = val; results }

...OR...

results = {}

File.open(file_name) do |file|
       file.each do |line|
             line.chomp!
             key, val = line.split(/=/)
             results[key] = val
      end
end

results

···

On Oct 11, 2005, at 4:06 PM, Jeff Carlson wrote:

Oops, I meant the *getMapFromFile* function. If I could see the ruby way of writing a method to take a file of the form
key1=value1
key2=value2
etc
and easily make it into a hash in a concise way (as in the python example) that would be great.

Jeff Carlson wrote:

I am very new to ruby and thought I would start with my simplest python script and port it over and along the way, learn the "ruby way" of doing things. My solution so far is unsatisfactory and long. If you have any suggestions, most especially about the "ruby way" to write the file2Map method, I would appreciate it and all of my future ruby programs would also appreciate it.
Cheers,
Jeff Carlson
-------------------------------------------------------------
#!/usr/bin/python
# print statistics for seti@home jobs
from mx.DateTime import TimeDelta
import sys
# this method takes a file with key/value pairs, seperated by "="
# and makes a map of the file, keys and values, the length of the
# map is the length of the file
def getMapFromFile(fname):
    lines = open(fname).readlines()
        return dict([line.split("=") for line in lines])
# make maps of the two files
sMap = getMapFromFile(sys.argv[1])
uMap = getMapFromFile(sys.argv[2])
prog = float(sMap["prog"].strip())*100
et = TimeDelta(seconds=float(sMap["cpu"].strip()))
#print results
print '%.2f%c completed in %d:%02d:%02d' % (prog, '%', et.hour, /
    et.minute, et.second)
print 'units of work so far %s' % (uMap["nresults"].strip())

Pretty much the same thing, but this should allow you to leave of some strips later, I hope:

def hash_from_file( file_name )
   Hash[*File.read(file_name).split("\n").map { |line| line.split("=") }.flatten]
end

James Edward Gray II

···

On Oct 11, 2005, at 3:16 PM, ES wrote:

def map_from(file)
  Hash[*File.readlines(file).map {|line| line.split '='}.flatten]
end

def hash_from_file(file_name)
  IO.read(file_name).inject({}) { |hash, line| hash.merge Hash[*line.split(/=/)] }
end

Devin

Jeff Carlson wrote:

···

Oops, I meant the *getMapFromFile* function. If I could see the ruby way of writing a method to take a file of the form
key1=value1
key2=value2
etc
and easily make it into a hash in a concise way (as in the python example) that would be great.

James Edward Gray II wrote:

···

On Oct 11, 2005, at 3:16 PM, ES wrote:

> def map_from(file)
> Hash[*File.readlines(file).map {|line| line.split '='}.flatten]
> end

Pretty much the same thing, but this should allow you to leave of
some strips later, I hope:

def hash_from_file( file_name )
   Hash[*File.read(file_name).split("\n").map { |line| line.split
("=") }.flatten]
end

James Edward Gray II

Erm, what do you mean "to leave of some strips"? The only difference I
can see is readlines(file) -> read(file_name).split("\n"), and I'm not
sure what the difference is.

Let's ask Ruby:

Neo:~/Desktop$ cat multiline_data.rb
#!/usr/local/bin/ruby -w

data = DATA.pos

p DATA.readlines

DATA.seek data

p DATA.read.split("\n")

__END__
Line one.
Line two.
Line three.
Neo:~/Desktop$ ruby multiline_data.rb
["Line one.\n", "Line two.\n", "Line three.\n"]
["Line one.", "Line two.", "Line three."]

If you go back and look at the original code now, I was hoping that would save all the random calls to strip() when Hash data is accessed, thought the "=" split() pattern may also need to become /\s*=\s*/ to get leading whitespace.

James Edward Gray II

···

On Oct 11, 2005, at 7:06 PM, Kevin Ballard wrote:

James Edward Gray II wrote:

On Oct 11, 2005, at 3:16 PM, ES wrote:

Pretty much the same thing, but this should allow you to leave of
some strips later, I hope:

def hash_from_file( file_name )
   Hash[*File.read(file_name).split("\n").map { |line| line.split
("=") }.flatten]
end

James Edward Gray II

Erm, what do you mean "to leave of some strips"? The only difference I
can see is readlines(file) -> read(file_name).split("\n"), and I'm not
sure what the difference is.

James Edward Gray II wrote:

If you go back and look at the original code now, I was hoping that
would save all the random calls to strip() when Hash data is
accessed, thought the "=" split() pattern may also need to become /
\s*=\s*/ to get leading whitespace.

Ohh, leave *off* some strips. I see what you mean.

Perhaps an easier solution would be to just use readlines, but then
call strip() on both key and value? That takes care of any whitespace,
whether it be leading the line, trailing, or around the equals sign.

James Edward Gray II wrote:

If you go back and look at the original code now, I was hoping that
would save all the random calls to strip() when Hash data is
accessed, thought the "=" split() pattern may also need to become /
\s*=\s*/ to get leading whitespace.

Ohh, leave *off* some strips. I see what you mean.

Ah, I see now. You're right, that was a terrible typo on my part! :frowning:

Perhaps an easier solution would be to just use readlines, but then
call strip() on both key and value? That takes care of any whitespace,
whether it be leading the line, trailing, or around the equals sign.

Yes, definitely.

James Edward Gray II

···

On Oct 12, 2005, at 11:36 AM, Kevin Ballard wrote: