SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    How do you populate a hash from a file?

    I want to be able to fill a hash with values from a file. Let's say that the hash contains a persons name, and their age. If a new entry gets added to the hash, I also want to add that same entry to the file. I haven't seen any good examples, and I'm totally lost. Can anyone provide a simple example?

  2. #2
    SitePoint Wizard chris_fuel's Avatar
    Join Date
    May 2006
    Location
    Ventura, CA
    Posts
    2,750
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What is the exact format of the file? CSV? Tab Seperated?

  3. #3
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just a .txt file with fixed width fields. Name = pos 1-30, age = pos 31-32, misc = pos 33-200.

  4. #4
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    open(the_file, 'r') do |f|
      data = f.map do |l|
        {:name => l[0..30],
         :age => l[31..32].to_i,
         :misc => l[33..200]}
      end
    end

  5. #5
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you. Would I do the same thing in reverse to write a record to the file?

  6. #6
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You can use ljust like this:

    Code:
    p = {:name => 'Foo', :age => 45, :misc => '...'}
    p[:name].ljust(30) + p[:age].to_s.ljust(2) + p[:misc].ljust(200)
    str.ljust(n) adds spaces to str so that it will have length n.

    Alternatively you can use these procedures, which use pack and unpack:

    Code:
    $format = 'A30A2A200'
    
    def load_data(file)
      open(file, 'r').map{|l| l.unpack($format)}
    end
    
    def save_data(file, data)
      open(file, 'w').write(data.map{|l| l.pack($format)})
    end

  7. #7
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ARRGGGHHH!! I can't get any of the examples to work!! I can't believe it is so hard to just open a file, read the records into a storage area, and close the file. All the tutorials I can find use cutsey examples that are meaningless in the real world, and aren't good for anything. I also can't fine any tutorials with good sections on file handling. I'm so frustrated, I'm about to give up.
    Last edited by jeryst; Sep 18, 2006 at 08:48.

  8. #8
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Try this one:

    Code:
    $format = 'A30A2A200'
    
    def load_data(file)
      open(file, 'r').map{|l| l.unpack($format)}
    end
    
    def save_data(file, data)
      open(file, 'w'){|f| f.write(data.map{|l| l.pack($format)}.join("\n"))}
    end
    
    data = [
    	['Foo', '23', 'bla bla...'],
    	['Bar', '43', 'baz baz...']
    ]
    
    save_data('records.txt', data)
    
    ldata = load_data('records.txt')
    p ldata

  9. #9
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thankyou for the help. I decided to work on a simpler example, for now.

    After a lot of experimentation, I am able to retrieve a record from a flat file, and populate a hash record with a key and value. My problem, now, is that no matter what I try, I can only get one record to populate correctly. I have tried every combination of looping that I can think of, but nothing works. If anyone wants to help, here are the specifics...

    I have a data file, named "modeldata.txt" containing the following 6 records...
    aaaAAA
    bbbBBB
    cccCCC
    dddDDD
    eeeEEE
    fffFFF

    Now, here is my program ...

    Code:
    $myhash = {}
    $myhash.default = "unknown"
    
    def load_data
      open("modeldata.txt", 'r') {|x| x.readline}
      end
    
    def parse_data 
    	g = load_data
    	g1=g[0..2]
    	g2=g[3..5]
    	$myhash[g1] = g2
    	$myhash.each_pair {|key, value| puts "key is #{key} and value is #{value}" }
    end
    
    #main logic-------------
    parse_data

    And here is my output...

    key is aaa and value is AAA

    How do I get the rest of the records into myhash? I know I'm probably not doing this correctly, but I'm still quite lost in this world.

  10. #10
    SitePoint Zealot
    Join Date
    Jul 2004
    Location
    Oklahoma
    Posts
    119
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    def parse_data (hash,line)
    	g1=line[0..2]
    	g2=line[3..5]
    	hash[g1] = g2
    	hash.each_pair {|key, value| puts "key is #{key} and value is #{value}" }
            return hash
    end
    
    #main logic-------------
    hash = Hash.new
    File.open("modeldata.txt", 'r') do |f|
            f.each do |x|
                   hash = parse_data(hash,x)
            end
    end
    I haven't tried actually running the above code, but it should give you more to go on as far as application structure anyway.

  11. #11
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I re-wrote your program. It's more functional-style now. This meant for me that it's easier to understand and to write (I find globals hard to understand). It was correct the first time I ran it because of this.

    First the parse_file procedure:

    Code:
    def parse_file(filename)
    	hash = {}
    	for line in open(filename)
    		hash[line[0..2]] = line[3..5]
    	end
    	return hash
    end
    This procedure has one argument: the filename of the file to parse. You call it like this: parse_file('modeldata.txt'). It creates a new hash variable. Then it loops over the lines in the file like this:

    Code:
    for line in open(filename)
      ...
    end
    open() doesn't need the 'r' argument if you read the file. You can also loop over the file line-by-line with for line in open(filename): you don't need readline or something like that. In the loop the program adds the data of this line to the hash.

    The display_data procedure:

    Code:
    def display_data(hash)
    	for key, value in hash
    		puts "#{key}: #{value}"
    	end
    end
    You can loop over a hash with for key, value in hash. The key will be assigned to "key" and the value to "value". It works like each_pair but it looks cleaner.

    The main logic:

    Code:
    display_data(parse_file('modeldata.txt'))
    The parse_file() procedure returns a hash, and this hash is printed by display_data().

    Full code:

    Code:
    def parse_file(filename)
    	hash = {}
    	for line in open(filename)
    		hash[line[0..2]] = line[3..5]
    	end
    	return hash
    end
    
    def display_data(hash)
    	for key, value in hash
    		puts "#{key}: #{value}"
    	end
    end
    
    display_data(parse_file('modeldata.txt'))

  12. #12
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you, this got it working for me. Perhaps you can answer me another question. I can write to the file, but when I do, it always appends it to the last line. I have tried all types of writes and modes, with the same result. Do you know how I can get it to write on a new line? Thanks again.

  13. #13
    SitePoint Guru
    Join Date
    Aug 2005
    Posts
    986
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You can use the puts procedure:

    Code:
    file = open(file, 'a')
    a.puts "something"
    This will add a newline after "something". So if you use it on an existing file it will still put "something" on the last line, and not on a new line. But it does add a newline so if the original file looked like this:

    Code:
    foo
    If you run the above script:

    Code:
    foosomething\n
    But there is a newline after foosomething! (note the \n) So if you run the script again:

    Code:
    foosomething\n
    something\n
    So now this is on a new line. (because the *previous* puts() added a newline)

    If you use the puts() procedure on an empty file it will work correctly, but if you use it on a hand-written file you should add a newline to the last line of the file.

    Edit: please let me know if this isn't clear.

  14. #14
    SitePoint Member
    Join Date
    Sep 2006
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you for the guidance. For the moment, I am no longer stuck in the loop of frustration, however, I am sure that it is only a temporary situation.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •