Set operations on Map - java

How can one perform set operations on a HashMap, such as Collections.addAll()?

Based on you comments to the questions asked I think what you really need is a Set not a Map.
Try
Set<String> mySet = new HashSet<String>();
mySet.addAll(...);
Use mySet.contains("someString"); for quick determination if a value exists. It should be equivalent of what you seem to be trying to do.

Through for instance Map.putAll.
You may also be able to do set-operations directly on the set of map entries which you can get hold of through Map.entrySet.
From the documentation:
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.

This way:
hashMap.putAll(map);
From documentation:
Copies all of the mappings from the
specified map to this map These
mappings will replace any mappings
that this map had for any of the keys
currently in the specified map.

You can do operations like
Map<String, String> map = new HashMap<String, String>();
Set<String> set = map.keySet();
for(String s: set);
set.retainAll(set2); // keeps the keys in set2
set.removeAll(set3); // removes the keys in set3
set.remove(s);
You can also turn a Map in a Set. There is no ConcurrentHashSet but you can do
Set<String> set = Collections.setFromMap(new ConcurrentHashMap<String, Boolean>());

Related

Java LinkedHashMap replace key

Is there any way to replace a key using put() in a LinkedHashMap without losing the order that the key was originally inserted in?
You do not lose the order when putting a different value for the same key.
Example
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("foo", "bar");
map.put("blah", "baz");
System.out.println(map);
map.put("foo", "foo");
System.out.println(map);
Output
{foo=bar, blah=baz}
{foo=foo, blah=baz}
Edit
"Replacing" a key for a given value would imply removing the key value pair, then putting the new key with the stored value.
As such, there is no direct way to do this with a LinkedHashMap, probably not even by inheriting and changing the behavior of remove and put.
If you used the LinkedHashMap, I don't think there is built-in method to achieve your goal. You may want to pick another (or design your own) data-structure.
If you have to do it on a linkedhashmap, you can create a new LinkedHashMap, iterate the old one and put into the new one, when your target entry comes, create a new entry with different key, put the new entry into the map.

Java How do I get all map values within specific keys?

right now I have a Map like this:
Map<Double, MyObject> map = new HashMap<Double, MyObject>();
I want to get all values of keys that are between 2.0 and 7.0. I have thousands of different values in my Map, so looping through every key-value set will be heavy for performance. Is there any way to solve this? (Or is there some sort of special map, that is used to have number keys?) Thanks for helping ;)
Use a TreeMap instead. Through its NavigableMap interface, you can perform range operations.
NavigableMap<Double, MyObject> map = new TreeMap<>();
Collection<MyObject> keys = map.subMap(2D, 7D).values();

Java: Setting key of a hashmap explicitly and keeping reference to it

public static HashMap<ArrayList<Integer>, String> map = new HashMap<ArrayList<Integer>, String>();
public static ArrayList<ArrayList<Integer>> keys = new ArrayList<>(map.keySet());
Then in main
map.put(key, "c");
(assume key is a valid ArrayList). But keys still has size 0 after that.
How can I make the relationship of keys stronger so that it will be actually tied to the HashMap and contain all its keys.
The copy constructor of ArrayList copies all the keys in the map to the ArrayList but if you change the map after that point it will not be reflected.
I can think of 3 options:
write your own map implementation that embeds an ArrayList and keeps it up to date
update the ArrayList manually everytime you update the map
don't use an ArrayList at all (keySet() is there when you need to access the keys so I'm not sure why you would need one)
You can't.
Map.keySet() returns the Map's current key set, which you then load into your list. Changes to the map after that have no effect on the contents of the list.
Most people would just re-get the key set if needed. Why don't you just do that?

Concurrent modification issue in map

I am using a concurrent hashmap of structure
Map<Set<Date>, Map<String, Object>> SampleMap
The Map used inside the given map (Map<String, Object>) is also a concurrent hashmap,
but set is a only TreeSet type.
Still I get concurrent Modification exception when I add following line in logs,
logger.debug("sampleMap.keySet() + ". Size is " + sampleMap.keySet().size()");
and also in some other parts of same class dealing with this map.
This map is extensively used in Batch process by multiple threads to put and remove values in map and java version used is 1.5.
I think the exception is due to Treeset and also i find there is no similar implementation of concurrent handling collection for type Set.
It would be great if any one confirm whether my thinking over given issue is correct and also please suggest solution for this problem?
Since you need to be able to "modify" the key, you need to follow this pattern
// lock the collection
Map<String, Object> values = map.remove(key);
key = new TreeSet<String>(key);
// modify copy of key
map.put(key, values);
// unlock the collection.
As you are performing an operation which ConcurrentMap does not support, you have to use your own locking. You can use a plain HashMap or LinkedHashMap with synchronized or ReentrantReadWriteLock.
You can create a Concurrent set using
// Added in Java 1.6
Set<String> set = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
// or to be sorted
Set<String> set = Collections.newSetFromMap(new ConcurrentSkipListMap<String, Boolean>());
However, you can't change the contents of a key so what you should be using is
Set<String> key = Collections.unmodifiableSet(treeSet);
// or to be sure its not modified
Set<String> key = Collections.unmodifiableSet(new TreeSet<String>(treeSet));
A simple example of why you cannot change a key after using it in a Map.
Set<String> key1 = new TreeSet<String>();
Map<Set<String>, Boolean> map = new ConcurrentHashMap<Set<String>, Boolean>();
map.put(key1, true);
System.out.println("Is the map ok? "+map.containsKey(key1));
key1.add("hello");
System.out.println("Is the map ok? "+map.containsKey(key1));
prints
Is the map ok? true
Is the map ok? false
The common behaviour is that it can no longer see the key in the map. This is because the map places the key into a bucket based on its hashCode. If the hashCode changes, it can be in the wrong bucket so when it looks for it, it can't find it.

Putting placeholders in a key/value List based on a Set of keys in Java

I have a Set of keys and a List of key/value pairs. The values are of the form Long,BigInteger.
// key/values pairs: Long,BigInteger
List<Object[]> values;
// id list that corresponds to the keys for the list above
Set<Long> ids;
If any member of the key Set does not exist as a key in the key/value list, I want to add it to the list with a value of 0.
What's a good way to do this in Java?
The various commenters suggesting maps make a good point. How about instead of
List<Object[]> values
you use
Map<Long, BigInteger> values
In that case:
for(Long id : ids) {
if(!values.containsKey(id)) {
values.put(id, BigInteger.ZERO);
}
}
In fact, even if the code as must be kept as written I'd consider using a map for manipulation by pre-processing the list into a map, then dumping it back into the list of object arrays.
What's a good way to do this in Java?
Replace the Set<Long> and List<Object[]> by a Map<Long, BigInteger>. If the ordering is not important, then use HashMap. If you'd like to sort automagically on keys, then use TreeMap. If you'd like to maintain insertion order, then use LinkedHashMap.
E.g.
Map<Long, BigInteger> unorderedMap = new HashMap<Long, BigInteger>();
Map<Long, BigInteger> orderedByKeys = new TreeMap<Long, BigInteger>();
Map<Long, BigInteger> orderedByInsertion = new LinkedHashMap<Long, BigInteger>();
This way you can just use any of the Map methods to handle key/value pairs. E.g.
Long key = 1L;
BigInteger value = map.get(key);
if (value == null) {
value = new BigInteger(0);
map.put(key, value);
}
You can even get all keys by Map#keySet():
Set<Long> keys = map.keySet();
To learn more about maps, consult Sun's own tutorial about the subject.
I think you want to use something like one of the Google Collections Multimap implementations. Don't re-invent the wheel. The Apache Commons has something similar I suspect, but I prefer the Google library.
Querying for a key that has no values returns an empty collection.
EDIT: options for sorting order, uniqueness, etc are all available, just pick the right implementation according to your requirements.

Categories