简体   繁体   中英

How do you assign new variable names when its already assigned to something? Ruby

The title really really doesn't explain things. My situation is that I would like to read a file and put the contents into a hash. Now, I want to make it clever, I want to create a loop that opens every file in a directory and put it into a hash. Problem is I don't know how to assign a name relative to the file name. eg:

hash={}  
Dir.glob(path + "*") do |datafile|
  file = File.open(datafile)
  file.each do |line|
    key, value = line.chomp("\t")
    # Problem here is that I wish to have a different
    # hash name for every file I loop through
    hash[key]=value
  end
  file.close
end

Is this possible?

Why don't you use a hash whose keys are the file names (in your case "datafile") and whose value are hashes in which you insert your data?

hash = Hash.new { |h, key| h[key] = Hash.new }  
Dir.glob(path + '*') do |datafile|
  next unless File.stat(datafile).file?
  File.open(datafile) do |file|
    file.each do |line|
      key, value = line.split("\t")
      puts key, value
      # Different hash name for every file is now hash[datafile]
      hash[datafile][key]=value
    end
  end
end

You want to dynamically create variables with the names of the files you process?

try this:

Dir.glob(path + "*") do |fileName|
  File.open(fileName) {

    # the variable `hash` and a variable named fileName will be
    # pointing to the same object... 
    hash = eval("#{fileName} = Hash.new")

    file.each do |line|
      key, value = line.chomp("\t")
      hash[key]=value
    end
  }
end

Of course you would have to make sure you rubify the filename first. A variable named "bla.txt" wouldn't be valid in ruby, neither would "path/to/bla.csv"

If you want to create a dynamic variable, you can also use #instance_variable_set (assuming that instance variables are also OK.

Dir.glob(path + "*") do |datafile|               
  file = File.open(datafile)                     
  hash = {}                                      
  file.each do |line|                            
    key, value = line.chomp("\t")                
    hash[key] = value                            
  end                                            
  instance_variable_set("@file_#{File.basename(datafile)}", hash)    
end

This only works when the filename is a valid Ruby variable name. Otherwise you would need some transformation.

Can't you just do the following?

filehash = {} # after the File.open line

...
# instead of hash[key] = value, next two lines
hash[datafile] = filehash
filehash[key] = value

You may want to use something like this:

hash[file] = {}
hash[file][key] = value

Two hashes is enough now. fileHash -> lineHash -> content.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM