开发者

Set<Integer> inside Map

开发者 https://www.devze.com 2023-01-19 07:03 出处:网络
I have a question. First, I declared a map: Map<TwoIntClass, Set<Integer>> m = new HashMap<TwoIntClass, Set<开发者_运维百科;Integer>>();

I have a question. First, I declared a map:

Map<TwoIntClass, Set<Integer>> m = new HashMap<TwoIntClass, Set<开发者_运维百科;Integer>>();

Now, I want to put stuff inside this map, something like

int num = 7;
m.put(new TwoIntClass(5, 3), ?? how to put num inside Set ??);

My question is, how do I put variable num inside Set. Thanks.


Like Jack and others have suggested, you need to instantiate a concrete instance of the Set interface (like HashSet), add your int values in the Set and then put the Set into your Map. However, if you are using a custom class for your Map's key, I would suggest you implement the equals() and hashCode() method of your TwoIntClass class to be sure that you are not creating duplicate entries inside your Map. For example, consider this class :

public class TwoIntClass {

    private int i1;
    private int i2;

    public TwoIntClass(int i1, int i2) {
        this.i1 = i1;
        this.i2 = i2;   
    }

    static public void main(String...args) {

        Map<TwoIntClass, Set<Integer>> map = new HashMap<TwoIntClass, Set<Integer>>();

        Set<Integer> dataset = new HashSet<Integer>();
        dataset.add(1);
        dataset.add(2);

        TwoIntClass i1 = new TwoIntClass(5, 3);
        TwoIntClass i2 = new TwoIntClass(5, 3);

        map.put(i1, dataset);
        map.put(i2, dataset);

        System.out.println( i1.hashCode() + " = " + i2.hashCode() + " == " + i2.equals(i2) + " > map count = " + map.size() );

        TwoIntClass i3 = new TwoIntClass(5, 3);
        System.out.println("Looking for TwoIntClass(5,3)... " + map.containsKey(i3) );

    }
}

The output for executing it is :

1476323068 = 535746438 == false > map count = 2

Looking for TwoIntClass(5,3)... false

As you see, they both are "equal" (i.e. they both are constructed with the same integers), but they are distinct objects with different hash codes, therefore create two entries in the map. This could lead into possible data corruption in your application. Moreover, executing this line : map.get(new TwoIntClass(5,3)).add(3); will generate a NullPointerException because the key (it's hash) does not exist in the map. So, you need to implement the equals() and hashCode() methods to fix this, so any TwoIntClass constructed with the same integers will be considered equal. Something like :

@Override
public boolean equals(Object obj) {
    if (!(obj instanceof TwoIntClass)) {
        return false;
    }
    TwoIntClass other = (TwoIntClass) obj;

    return (other.i1 == this.i1) && (other.i2 == this.i2); 
}

@Override
public int hashCode() {
    //return TwoIntClass.class.hashCode() | i1 | (i2 << 16);

    // better implementation based on the String class
    int hash = TwoIntClass.class.hashCode();

    hash = (hash * 31) + i1;
    hash = (hash * 31) + i2;

    return hash;
}

yields a more expected result of

1476323071 = 1476323071 == true > map count = 1

Looking for TwoIntClass(5,3)... true

Of course, this hashCode() method is over simplistic and you may need to find a yet better construct, but the bottom line is that implementing them is what I would recommend.


Set set = new HashSet();
set.add(2);
set.add(4);
...
m.put(new TwoIntClass(5, 3), set);

Slightly better (from here):

m.put(new TwoIntClass(5, 3), new HashSet(Arrays.asList(1, 2)));

You can modify the set like this:

m.get(new TwoIntClass(5, 3)).add(6);


I'd recommend using a SetMultimap from Guava instead. This saves you from having to think about creating the sets yourself.

SetMultimap<TwoIntClass, Integer> multimap = HashMultimap.create();
TwoIntClass twoInts = new TwoIntClass(5, 3);
int num = 7;
multimap.put(twoInts, num);

Set<Integer> set = multimap.get(twoInts); // set contains 7

multimap.put(twoInts, 8);
multimap.put(twoInts, 9); // set now contains 7, 8 and 9


You have to be sure that the related Set is instantiated and inserted into the Map before doing anything. You could use something like

public void safeInsert(TwoIntClass tic, Integer element)
{
  if (!map.contains(tic))
    map.put(tic, new HashSet<Integer>());

  map.get(tic).add(element);
}

Mind that you can't use directly Set since it's an interface, so choose an actual implementation (eg. HashSet)

With Java8 every thing become easier:

map.computeIfAbsent(tic, k -> new HashSet<>()).add(element);


You will have to create the set first, add the item, and then put the set in the map. There is no good way to initialize a set inline in Java. (This may change when java 7 comes out.)

int num = 7;
Set<Integer> set = new HashSet<Integer>();
set.add(num);
m.put(new TwoIntClass(5, 3), set);


Each time you want to put something in the set, you need to check if the set already exists, and create the set if it does not. ie:


int num = 7;
TwoIntClass twoInt = new TwoIntClass(5, 3);
Set<Integer> intSet = m.get(twoInt);
if(num == null) {
  intSet = new HashSet<Integer>();
  intSet.put(twoInt, intSet);
}
intSet.add(num);

There's a perfect abstraction over this in google's guava libraries called SetMultimap that you should consider using, especially if this is a repeated pattern in your code.


int num = 7;
TwoIntClass twoInts = new TwoIntClass(5, 3);
m.put(twoInts, new HashSet<Integer>());
m.get(twoInts).add(num);
0

精彩评论

暂无评论...
验证码 换一张
取 消