The Whiz of Oz
The Whiz of Oz

Reputation: 7043

How to load an array from a file with Ruby?

I have a file which has an array of hashes in it:

[
  {key1: 'value', key2: 'value'},
  {key1: 'value', key2: 'value'},
  {key1: 'value', key2: 'value'}
  ...
]

I would like to load this entire array into a variable and make some manipulations with it. To be super concrete, I'd like to re-arrange the array alphabetically based on the key1. Read, readlines and each_line not working for me.

Upvotes: 1

Views: 1524

Answers (5)

Ajedi32
Ajedi32

Reputation: 48338

I recommend the following:

require 'yaml'
data = YAML.load_file '<filename>'
data.sort_by{|hash| hash[:key1]}

Your file looks quite a bit like JSON data, but includes a few minor formatting differences that make using a JSON parser impossible. Thankfully the data is perfectly valid YAML, so Ruby's YAML parser can read it just fine.

Upvotes: 1

Mori
Mori

Reputation: 27779

Since your file is valid Ruby, if it's from a trusted source you can just eval it:

my_sorted_array = eval(IO.read('test.txt')).sort_by { |e| e[:key1] }

Upvotes: 3

BroiSatse
BroiSatse

Reputation: 44675

It is recommended to store such a data in yaml format. Write the file like (mind the spacing!):

---
- :key1: value
  :key2: value
- :key1: value
  :key2: value
- :key1: value
  :key2: value

Then just do:

require 'yaml'
array = YAML.parse_file('/path/to/your/file')

To save data to such a file (require 'yaml' needed to run this as well):

File.open('/path/to/file', 'w') { |f| f.write array.to_yaml }

Upvotes: 2

Uri Agassi
Uri Agassi

Reputation: 37409

As a matter of rule, Hash.to_s is a one-way function - there is no easy way to parse it. Given that the format is plain, and as you stated, you can do something like this:

text = IO.read('test.txt')

# normalize text to a valid JSON:

# turns 'value' to "value"
text.gsub!("'", '"')
# turns key1: to "key1":
text.gsub!(/([{,])\s*([^{":\s]+)\s*:/, '\1 "\2":')

#parse it
array = JSON.parse(text)

sorted = array.sort_by { |h| h['key1'] }
# => [{"key1"=>"value1", "key2"=>"value"}, {"key1"=>"value2", "key2"=>"value"}, {"key1"=>"value3", "key2"=>"value"}]

Upvotes: 1

user3433919
user3433919

Reputation: 11

This should do it for you:

str = ""
File.open('<path_to_file>').each do |line|
  str += line.strip
end
hash_array = eval(str)
hash_array.sort_by!{|t| t[:key1]}

Sorry about the prior answer.

Upvotes: 0

Related Questions