package maps;

import java.util.*;

public class MultiMap {
    public static void main(String[] args) {
        Map<String, String> m1 = new HashMap<String, String>();
        m1.put("Smith", "Matt");
        m1.put("Brown", "Bob");
        m1.put("Clinton", "Hilllary");

        Map<String, String> m2 = new HashMap<String, String>();
        m2.put("Smith", "Joseph");
        m2.put("Brown", "Brent");
        m2.put("Clinton", "Bill");

        Map<String, String> m3 = new HashMap<String, String>();
        m3.put("Jordan", "Michael");
        m3.put("Wade", "Dwayne");
        m3.put("Woods", "Tiger");

        List<Map<String, String>> l = new ArrayList<Map<String, String>>();
        l.add(m1);
        l.add(m2);
        l.add(m3);

        Map<String, List<String>> all = combine(l);
        System.out.println(all);

        all = combineG(l);
        System.out.println(all);
    }

    public static Map<String, List<String>> combine(
            List<Map<String, String>> mapsList) {
        Map<String, List<String>> all = new HashMap<String, List<String>>();

        for (Map<String, String> m : mapsList) { // iterate through list
            for (Map.Entry<String, String> e : m.entrySet()) { // iterate through map entries
                String key = e.getKey();
                String value = e.getValue();
                if (all.containsKey(key)) { //check for the key
                    List<String> keyValuesList = all.get(key);
                    keyValuesList.add(value); //add the value to the list
                } else { //create a new list and add the value to it
                    List<String> keyValuesList = new ArrayList<String>();
                    keyValuesList.add(value);
                    all.put(key, keyValuesList);
                }
            }
        }
        return all;
    }

    /**
     * Generic function that takes a list of maps, combines them, and returns a map
     * with keys of K corresponding Lists of V (Thanks to Josh Elliott)
     */
    public static <K, V> Map<K, List<V>> combineG(List<Map<K, V>> list) {

        Map<K, List<V>> result = new HashMap<K, List<V>>();

        for (Map<K, V> m : list) {
            for (Map.Entry<K, V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                if (result.containsKey(key)) {
                    List<V> keyValuesList = result.get(key);
                    keyValuesList.add(value);
                } else {
                    List<V> keyValuesList = new ArrayList<V>();
                    keyValuesList.add(m.get(key));
                    result.put(key, keyValuesList);
                }
            }
        }

        return result;
    }
}
