0

Sample hash:

  {
    "audio" =>  {
      "audio/aac" => ["aac"],
      "audio/mpeg" => ["mp3", "mp2"],
      "audio/mp4" => ["m4a", "m4b", "m4r", "3gp"],
      "audio/ogg" => ["ogg", "oga"],
      "audio/flac" => ["flac"],
      "audio/speex" => ["spx"],
      "audio/x-ms-wma" => ["wma"],
      "audio/x-pn-realaudio" => ["rm", "ram"],
      "audio/vnd.wave" => ["wav"],
      "audio/x-musepack" => ["mpc", "mp+", "mpp"],
      "audio/x-aiff" => ["aiff", "aif", "aifc"],
      "audio/x-tta" => ["tta"]
    },
    "video" =>  {
      "video/mp4" => ["mp4"],
      "video/mpeg" => ["mpg", "mpeg"],
      "video/x-m4v" => ["m4v"],
      "video/quicktime" => ["mov"],
      "video/x-msvideo" => ["avi"],
      "video/x-flv" => ["flv"],
      "video/webm" => ["webm"]
    }
  }

What's the best way given a file extension to get the associated content type (first match is okay)?

Searching for "flac" should return "audio/flac".

Currently I'm using this:

hsh.each_key do |group|
  hsh[group].each do |k,v|
    return k if v.include?(extension)
  end
end

3 Answers 3

4

Unraveling that sort of structure is best done when it's created. But, you can loop through the various levels and get something useful from it. If I assign your initial hash to mime_hash I can unravel it using:

Hash[*mime_hash.map{ |av, types| types.map{ |mime_type, extensions| extensions.product([mime_type]) } }.flatten] 

or more verbosely:

Hash[
  *mime_hash.map{ |av, types| 
    types.map{ |mime_type, extensions| 
      extensions.product([mime_type]) 
    } 
  }.flatten
] 

Which will return:

{
     "aac" => "audio/aac",
     "mp3" => "audio/mpeg",
     "mp2" => "audio/mpeg",
     "m4a" => "audio/mp4",
     "m4b" => "audio/mp4",
     "m4r" => "audio/mp4",
     "3gp" => "audio/mp4",
     "ogg" => "audio/ogg",
     "oga" => "audio/ogg",
    "flac" => "audio/flac",
     "spx" => "audio/speex",
     "wma" => "audio/x-ms-wma",
      "rm" => "audio/x-pn-realaudio",
     "ram" => "audio/x-pn-realaudio",
     "wav" => "audio/vnd.wave",
     "mpc" => "audio/x-musepack",
     "mp+" => "audio/x-musepack",
     "mpp" => "audio/x-musepack",
    "aiff" => "audio/x-aiff",
     "aif" => "audio/x-aiff",
    "aifc" => "audio/x-aiff",
     "tta" => "audio/x-tta",
     "mp4" => "video/mp4",
     "mpg" => "video/mpeg",
    "mpeg" => "video/mpeg",
     "m4v" => "video/x-m4v",
     "mov" => "video/quicktime",
     "avi" => "video/x-msvideo",
     "flv" => "video/x-flv",
    "webm" => "video/webm"
}
Sign up to request clarification or add additional context in comments.

2 Comments

Nice, didn't know about Array#product.
map + flatten(1) = flat_map. Hash[...] takes pairs, no need to do a total flatten.
0

As you've already realized the data structure you have is horrible to search in the fashion you want. Assuming you're going to be searching the same data over and over what you should do is create an index for it.

There are many ways of doing this but the simplest is probably just to flatten the hash and invert it so that your keys become values and vice-versa. That way you can simply search it by calling content_types['flac']

A section of the example hash might end up like this:

{
  "aac" => "audio/aac",
  "mp3" => "audio/mpeg",
  "mp2" => "audio/mpeg",
  "m4a" => "audio/mp4",
  "m4b" => "audio/mp4",
  "m4r" => "audio/mp4",
  "3gp" => "audio/mp4",
  "flac" => "audio/flac"
}

1 Comment

Yes, the structure is not ideal, but it serves mainly for other purposes (hence the audio/video groups) in the app, and was not meant to be asked for mime type resolution by ext.
0

Try using rassoc()

Definition:

Searches through the hash comparing obj with the value using ==. Returns the first key-value pair (two-element array) that matches. See also Array#rassoc.

a = {1=> "one", 2 => "two", 3 => "three", "ii" => "two"}
a.rassoc("two")    #=> [2, "two"]
a.rassoc("four")   #=> nil

1 Comment

I'm afraid that doesn't quite work as expected on this kind of hash. If the keys are an array it becomes a problem since hash["audio"].rassoc(["m4b"]) won't return anything. Do you have an example?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.