Phrogz Phrogz - 10 months ago 32
Ruby Question

Functionally find mapping of first value that passes a test

In Ruby, I have an array of simple values (possible encodings):

encodings = %w[ utf-8 iso-8859-1 macroman ]

I want to keep reading a file from disk until the results are valid. I could do this:

good = encodings.find{ |enc|, "r:#{enc}").valid_encoding? }
contents =, "r:#{good}")

...but of course this is dumb, since it reads the file twice for the good encoding. I could program it in gross procedural style like so:

contents = nil
encodings.each do |enc|
if (, "r:#{enc}")).valid_encoding?
contents = s

But I want a functional solution. I could do it functionally like so:

contents ={|e|, "r:#{e}")}.find{|s| s.valid_encoding? }

…but of course that keeps reading files for every encoding, even if the first was valid.

Is there a simple pattern that is functional, but does not keep reading the file after a the first success is found?


If you sprinkle a lazy in there, map will only consume those elements of the array that are used by find - i.e. once find stops, map stops as well. So this will do what you want:

possible_reads = {|e|, "r:#{e}")}
contents = possible_reads.find {|s| s.valid_encoding? }