2

Is it possible to get list of values from HashMap as a reference

class MyCustomObject {
    String name;
    Integer id;

    MyCustomObject(String name, Integer id){
        this.name = name;
        this.id = id;
    }
}
HashMap<Integer, MyCustomObject> map = new LinkedHashMap<>();
map.put (1, new MyCustomObject("abc",1));
map.put (2, new MyCustomObject("xyz",2));

List<MyCustomObject> list = new ArrayList<>(map.values());

Log.i(TAG,"************ List from HashMap ************");
for (MyCustomObject s : list) {
     Log.i(TAG,"name = "+s.name);
}

list.set(0,new MyCustomObject("temp",3));

Log.i(TAG,"************ List from HashMap after update ************");
for (MyCustomObject s : list) {
      Log.i(TAG,"name = "+s.name);
}

Log.i(TAG,"************ List from HashMap ************");

List<MyCustomObject> list2 = new ArrayList<>(map.values());
for (MyCustomObject s : list2) {
     Log.i(TAG,"name = "+s.name);
}

Output

**************** List from HashMap ***************
name = abc
name = xyz
**************** List from HashMap after update ***************
name = temp
name = xyz
**************** List from HashMap ***************
name = abc
name = xyz

Here if get list of values from HashMap it return deep-copy.

Update

My Requirement

  1. I want list of values from HashMap because I want to access items using their position
  2. I want to preserve order of values
  3. If I modify anything in the extracted list then it should reflect in HashMap too

Please do tell, if any third party library provide such data structure, or what would be best approach to handle this situation

  • 2
    `List list = new ArrayList<>(map.values());` What do you think this line does? – Fildor Jun 21 '16 at 11:09
  • It is shallow copy, what exactly do you want? – Boola Jun 21 '16 at 11:11
  • Spoiler: https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection) – Fildor Jun 21 '16 at 11:12
  • The problem is that a hashmap doesn't know about indices so you can't get a list which is backed by the map. Even if it were possible `list.set(0, whatever)` doesn't make much sense with a map since you'd need to access/check the key anyways and in that case you can just call `map.put(key, whatever)`. – Thomas Jun 21 '16 at 11:12
  • What i want is, if i update MyCustomObject from list, it should reflect in HashMap too –  Jun 21 '16 at 11:12
  • So by setting the element at ```0```, you want it to remove that element, and add the new one to the hashmap? Even if they don't have the same key? And btw, HashMap is unordered, there is no need to preserve the order of values. – Jorn Vernee Jun 21 '16 at 11:22
  • @JornVernee LinkedHashMap preserve order –  Jun 21 '16 at 11:33
  • Sorry, didn't see that – Jorn Vernee Jun 21 '16 at 11:36

3 Answers3

5

You are creating an new List based on the values of the Map :

List<MyCustomObject> list = new ArrayList<>(map.values());

That's what creates the copy of the values Collection, and changes in that List cannot be reflected in the original Map.

If you modify the Collection returned by map.values() directly (for example, map.values().remove(new MyCustomObject("abc",1))), it will be reflected in the contents of the original Map. You wouldn't be able to call set on the Collection, though, since Collection doesn't have that method.

Eran
  • 387,369
  • 54
  • 702
  • 768
3

Collection values()

Returns a Collection view of the values contained in this map. The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa.

So use a Collection and assign values() to it. Or the entrySet().

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
1

Try using the map entries which are backed by the map and which you get by calling entrySet(). A list of those almost works like you want it to do (although I'd still advocate you directly use map.put( key, updatedValue ).

Example:

Map<String, Integer> map = new HashMap<>();
map.put( "a", 1 );
map.put( "b", 2 );

//you create a list that's not backed by the map here but that isn't a problem
//since the list elements, i.e. the entries, are backed by the map
List<Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet());
entryList.get(0).setValue( 5 );

System.out.println( map ); //prints: {a=5, b=2} (note that order is a coincidence here)

One final note though: as I already stated in my comment when dealing with a map order is not always deterministic (unless you know you're dealing with an ordered map like TreeMap) and thus using indices may introduces bugs or undesired behavior. That's why you'll want to at least check the key in most cases and thus you either need to use Map.Entry (which btw can't have its key altered, for good reasons) or use the key directly in which case you don't need a list/collection of values or entries anyways.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • This is closest to what i need –  Jun 21 '16 at 11:25
  • Will order be deterministic if i use LinkedHashMap instead of HashMap ? Will map.entrySet() provide data in same order always –  Jun 21 '16 at 12:03
  • http://stackoverflow.com/questions/2923856/is-the-order-guaranteed-for-the-return-of-keys-and-values-from-a-linkedhashmap-o/2924143#2924143 –  Jun 21 '16 at 12:12
  • @penguin a `LinkedHashMap` has a deterministic order but it might still not be known by the algorithm that is meant to handle the list index. Besides that `LinkedHashMap` is more of a compromise/hybrid and as far as the map part goes indices don't have a meaning. That said I find it dangerous to rely on a compromise or a property of a collection that is not meant to be used that way. – Thomas Jun 21 '16 at 12:26