简体   繁体   中英

Combine hash keys if values are same

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.

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"
}
h.inject({}) {|r,(k,v)| r[h.select {|_,_v| _v == v}.keys.join(', ')] = v; r}

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);
{"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
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM