I'm golfing some code while waiting for a coworker, and I shortened a function to this:
def get_data(dir)
newest = get_most_recent_file_numbers(dir)
data = {}
$file_prefixes.each do |type, file_prefix|
file = File.open("#{dir}/#{file_prefix}_#{newest[type]}.csv")
file.readline
data[type] = file.readlines
end
data
end
I feel like there must be some method to do away with that last line of just data
. How can I get $file_prefixes.each
to return data
?
If it matters, $file_prefixes
looks like this:
$file_prefixes = {
:fixed_deal => "PC2MMS_CMSS_DEALS_",
:fixed_offer => "PC2MMS_CMSS_OFFERS_",
:mobile_deal => "PC2MMS_NGBSS_DEALS_",
:mobile_offer => "PC2MMS_NGBSS_OFFERS_"
}
and newest
is pretty much identical.
My target code might look something like this:
def get_data(dir)
newest = get_most_recent_file_numbers(dir)
data = {} # might even be able to get rid of this with clever use of Hash.new
data = $file_prefixes.each do |type, file_prefix|
file = File.open("#{dir}/#{file_prefix}_#{newest[type]}.csv")
file.readline
???
end
end
Disclaimer: I'm aware I could golf more by using single letter names, but I'm just trying to get it succinct and still readable
2 Answers 2
Some notes:
- Avoid the pattern init + each + update. Use
map
or other functional methods. - In Ruby>= 2.1.0 you have
Array#to_h
. UseHash[...]
in older Rubies. - Use
File.join
I'd write:
def get_data(dir)
newest = get_most_recent_file_numbers(dir)
$file_prefixes.map do |type, file_prefix|
path = File.join(dir, file_prefix + "_" + newest[type] + ".csv")
[type, File.readlines(path)]
end.to_h
end
-
\$\begingroup\$ Hmmm... I need to discard the first line of the file, and I don't see a way to sneak that single readline in here without disrupting your logic. Perhaps I can just set the start for readlines at the first line someway? \$\endgroup\$Devon Parsons– Devon Parsons2014年10月03日 18:24:58 +00:00Commented Oct 3, 2014 at 18:24
-
\$\begingroup\$ Aha! I can just change that last line to
[type, File.readlines(path)[1,-1]]
. Perfect! \$\endgroup\$Devon Parsons– Devon Parsons2014年10月03日 18:27:15 +00:00Commented Oct 3, 2014 at 18:27
tokland's answer is fine, but I thought I'd chime in and suggest using Enumerable#each_with_object
instead of converting your data into an array and back.
def get_data(dir)
newest = get_most_recent_file_numbers(dir)
$file_prefixes.each_with_object({}) do |mapping, hash|
file = File.read("#{dir}/#{mapping.first}_#{newest[mapping.last]}
end
end
In this example, I'm just using each_with_object
to construct a new hash and populate it with values. You can also get rid of the need to call file = File.open ... file.readlines
by just using File.read
to get the same output.