HashMap with multiple values under the same key

2018-12-31 16:42发布

Is it possible for us to implement a HashMap with one key and two values. Just as HashMap?

Please do help me, also by telling (if there is no way) any other way to implement the storage of three values with one as the key?

标签: java
19条回答
初与友歌
2楼-- · 2018-12-31 16:43

Yes and no. The solution is to build a Wrapper clas for your values that contains the 2 (3, or more) values that correspond to your key.

查看更多
不流泪的眼
3楼-- · 2018-12-31 16:45

We can create a class to have multiple keys or values and the object of this class can be used as a parameter in map. You can refer to https://stackoverflow.com/a/44181931/8065321

查看更多
大哥的爱人
4楼-- · 2018-12-31 16:46

No, not just as a HashMap. You'd basically need a HashMap from a key to a collection of values.

If you're happy to use external libraries, Guava has exactly this concept in Multimap with implementations such as ArrayListMultimap and HashMultimap.

查看更多
零度萤火
5楼-- · 2018-12-31 16:47

You could:

  1. Use a map that has a list as the value. Map<KeyType, List<ValueType>>.
  2. Create a new wrapper class and place instances of this wrapper in the map. Map<KeyType, WrapperType>.
  3. Use a tuple like class (saves creating lots of wrappers). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. Use mulitple maps side-by-side.

Examples

1. Map with list as the value

// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();    

// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);

// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];

The disadvantage with this approach is that the list is not bound to exactly two values.

2. Using wrapper class

// define our wrapper
class Wrapper {
    public Wrapper(Person person1, Person person2) {
       this.person1 = person1;
       this.person2 = person2;
    }

    public Person getPerson1 { return this.person1; }
    public Person getPerson2 { return this.person2; }

    private Person person1;
    private Person person2;
}

// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();

// populate it
Wrapper people = new Wrapper()
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
                                        new Person("Bob Jones"));

// read from it
Wrapper bobs = peopleByForename["Bob"];
Person bob1 = bobs.Person1;
Person bob2 = bobs.Person2;

The disadvantage to this approach is that you have to write a lot of boiler-plate code for all of these very simple container classes.

3. Using a tuple

// you'll have to write or download a Tuple class in Java, (.NET ships with one)

// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();

// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
                                       new Person("Bob Jones"));

// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;

This is the best solution in my opinion.

4. Multiple maps

// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();

// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));

// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];

The disadvantage of this solution is that it's not obvious that the two maps are related, a programmatic error could see the two maps get out of sync.

查看更多
情到深处是孤独
6楼-- · 2018-12-31 16:48

Just for the record, the pure JDK8 solution would be to use Map::compute method:

map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);

Such as

public static void main(String[] args) {
    Map<String, List<String>> map = new HashMap<>();

    put(map, "first", "hello");
    put(map, "first", "foo");
    put(map, "bar", "foo");
    put(map, "first", "hello");

    map.forEach((s, strings) -> {
        System.out.print(s + ": ");
        System.out.println(strings.stream().collect(Collectors.joining(", ")));
    });
}

private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
    map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}

with output:

bar: foo
first: hello, foo, hello

Note that to ensure consistency in case multiple threads access this data structure, ConcurrentHashMap and CopyOnWriteArrayList for instance need to be used.

查看更多
孤独总比滥情好
7楼-- · 2018-12-31 16:49

I am so used to just doing this with a Data Dictionary in Objective C. It was harder to get a similar result in Java for Android. I ended up creating a custom class, and then just doing a hashmap of my custom class.

public class Test1 {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.addview);

//create the datastring
    HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
    hm.put(1, new myClass("Car", "Small", 3000));
    hm.put(2, new myClass("Truck", "Large", 4000));
    hm.put(3, new myClass("Motorcycle", "Small", 1000));

//pull the datastring back for a specific item.
//also can edit the data using the set methods.  this just shows getting it for display.
    myClass test1 = hm.get(1);
    String testitem = test1.getItem();
    int testprice = test1.getPrice();
    Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}

//custom class.  You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
    private String item;
    private String type;
    private int price;

    public myClass(String itm, String ty, int pr){
        this.item = itm;
        this.price = pr;
        this.type = ty;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public String getType() {
        return item;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}
查看更多
登录 后发表回答