Reputation: 7043
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
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
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
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
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
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