0

I need to take a hash like this:

{"10am - 2pm"=>"Sun - Sat", "5pm - 7pm"=>"Sun - Sat"}

and create a new hash like this:

{"10am - 2pm, 5pm - 7pm"=>"Sun - Sat"}

If any values are the same amongst members in a hash, I need to combine the keys and remove the duplicate.

sawa
  • 165,429
  • 45
  • 277
  • 381
djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • 1
    Why a hash? Are you keeping track of each key and need to be able to access it rapidly? Or, are you using a hash as a queue and eventually need to walk through it and process each entry separately? Modifying the keys like that smells a lot like using the hash as a queue, which is really what an Array is for. – the Tin Man Mar 08 '13 at 22:20
  • 3
    Why combine them into a string when you can use arrays as keys in a Ruby hash? – mu is too short Mar 08 '13 at 22:23
  • @theTinMan, I'm reformatting data I'm getting back from an API. In that data, multiple days will have the same hours of operation, so I key off the hours of operation to get an array of days. the structure i pasted here is what happens further down the line, when i've converted raw day digits into day words, with spans (Sun - Sat). – djibouti33 Mar 09 '13 at 00:33

5 Answers5

3

There's probably something simpler, and maybe one of the really smart folks will wander by with something cool and zen-like but this works for now:

hash = {"10am - 2pm"=>"Sun - Sat", "5pm - 7pm"=>"Sun - Sat"}
hash.group_by{ |k,v| v }.each_with_object({}) { |(k,v), h| h[v.map(&:first).join(', ')] = k }

Which generates:

{
    "10am - 2pm, 5pm - 7pm" => "Sun - Sat"
}

@muistooshort makes a good point:

Why combine them into a string when you can use arrays as keys in a Ruby hash?

hash.group_by{ |k,v| v }.each_with_object({}) { |(k,v), h| h[v.map(&:first)] = k }
{
    [ "10am - 2pm", "5pm - 7pm" ] => "Sun - Sat"
}
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
3
h.inject({}) {|r,(k,v)| r[h.select {|_,_v| _v == v}.keys.join(', ')] = v; r}
Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32
0

I don't know ruby syntax but I would make a new hash where keys are values, and values are keys, then group the new hash again into arrays where now values are keys and keys are values :P

EDIT:

for those downvotes, yes I don't know ruby, but whats wrong with trying to give an idea to solve the problem?? OP doesn't have to accept mine as answer.

here's the code:

HashMap<String, String> hash = new HashMap<String, String>();
        HashMap<String, ArrayList> nhash = new HashMap<String, ArrayList>();
        HashMap<String, String> fhash = new HashMap<String, String>();

        hash.put("10am - 2pm", "Sun - Sat");
        hash.put("5pm - 7pm", "Sun - Sat");

        Iterator it = hash.keySet().iterator();
        while(it.hasNext()){
            String k =it.next().toString();
            String v=hash.get(k);
            if(nhash.get(v)==null){
                ArrayList a = new ArrayList();
                nhash.put(v, a);
                nhash.get(v).add(k);
            }else{
                nhash.get(v).add(k);
            }
        }

        Iterator nit = nhash.keySet().iterator();
        while(nit.hasNext()){
            String k =nit.next().toString();
            ArrayList v=nhash.get(k);
                fhash.put(v.toString(), k);

        }

        System.out.println(fhash);
Yichz
  • 9,250
  • 10
  • 54
  • 92
  • honestly I don't know what's wrong with my logic for downvote, will be appreciate to point out. I just did that and worked – Yichz Mar 08 '13 at 22:31
  • Yes, it seems very simple, so show some code, which is what the OP is looking for. – the Tin Man Mar 08 '13 at 22:33
  • @theTinMan, he say he don't know ruby so we can't expect "some code" ( – SET001 Mar 08 '13 at 22:40
  • If you can't answer the question in the correct language, perhaps you should use pseudocode? This sort of answer could really confuse a noob. Or at least mention what language you DID use! – adamwong246 Oct 31 '13 at 21:50
0
{"10am - 2pm"=>"Sun - Sat", "5pm - 7pm"=>"Sun - Sat"}
.inject({}){|h, (k, v)|
   _k = h.key(v)
   h.delete(_k)
   h[[*_k, k].join(", ")] = v
   h
}
sawa
  • 165,429
  • 45
  • 277
  • 381
0

I won't be voting on my own solution because I changed the requirements, (which actually helped me out later on in my code), but here's what I ended up doing:

h = {"10am - 2pm"=>"Sun - Sat", "5pm - 7pm"=>"Sun - Sat"}
h.reduce({}) { |h, (k,v)| (h[v] ||= []) << k; h}.reduce({}) {|h, (k,v)| h[k] = v.join(', '); h}
# {"Sun - Sat"=>"10am - 2pm, 5pm - 7pm"} 

I can't just call invert because the values that are duplicated get squashed into one member in the new hash. So I'm inverting while preserving each component (in an array), then joining that array to make the string I was looking for.

djibouti33
  • 12,102
  • 9
  • 83
  • 116