I need to write a small snippet of code where I need to check contents of a map (key value) if it exists in another map , remove it from the map
E.g
Map1:
1=>obj1
2=>obj21
3=>obj3
4=>obj4
Other map
Map2:
10=>obj10
20=>obj20
2=>obj2
30=>obj30
3=>obj3
The result of fun (Map1, Map2)
after it executes it has the following ouput
Map2:
10=>obj10
2=>obj2
20=>obj20
30=>obj30
Is iterating over the smaller map and checking contents (key, value) is iterating over the smaller map and checking the key and contents in the bigger map the most efficient way to go about it.
m1.entrySet().removeAll(m2.entrySet());
where m1 is the Map to be modified, and m2 is the map with the mappings that need to be removed from m1.
private static <K, V> void fun(Map<K, V> a, Map<K, V> b) {
Map<K, V> shortestMap = a.size() < b.size() ? a : b;
Map<K, V> longestMap = a.size() > b.size() ? a : b;
Set<Entry<K, V>> shortestMapEntries = shortestMap.entrySet();
Set<Entry<K, V>> longestMapEntries = longestMap.entrySet();
longestMapEntries.removeAll(shortestMapEntries);
}
See java.util.Collection
boolean removeAll(Collection<?> c)
private static <K, V> removeDuplicates(Map<K, V> map1, Map<K, V> map2) {
for (K key : map1.keySet()) {
V val1 = map1.get(key);
V val2 = map2.get(key);
if (val2 != null && val2.equals(val1)
map2.remove(key);
}
}
Related
public class CollectionUtils {
public static <K, V> Map<K, V> createMap(Iterable<V> values, Function<V, K> keyFunction, boolean skipNullKeys) {
Map<K, V> map = new HashMap<>();
for (V value : values) {
K key = keyFunction.apply(value);
if (key != null || !skipNullKeys) {
map.put(key, value);
}
}
return map;
}
I would use small and simple data, e. g.
List<Integer> values = Arrays.asList(1, null);
Function<Integer, String> toKey = String::valueOf;
Map<String, Integer> withNull = createMap(values, toKey, false);
Map<String, Integer> noNull = createMap(values, toKey, true);
Then you can test with Map#size, Map#containsKey (needed for null-key) and ...get("1").equals(1).
But as I mentioned in the comment, if your function may result in the same key for different values you only have the last value, e. g. Function<Integer, Integer> toKey = i -> i%2 will only procude 0 or 1 as a key (and a NullPointerException for null-values) so List<Integer> values = Arrays.asList(1, 3) will produce a Map with only one entry "1" -> 3.
Preface: This is not an actual problem that I have, it just came to my mind in a "What if... ...how would I do that?" fashion.
When I have Strings consisting of several key-value pairs (like 123=456;321=654;89=90), I can make a Map from that ({123=456, 321=654, 89=90}) pretty easily with a method like this:
public static Map<Integer, Integer> makeMap(String theString) {
String[] chunks = theString.split(";");
Map<Integer, Integer> result = new HashMap<>(chunks.length);
for (String chunk : chunks) {
String[] chunksChunks = chunk.split("=");
int key = Integer.parseInt(chunksChunks[0]);
int value = Integer.parseInt(chunksChunks[1]);
result.put(key, value);
}
return result;
}
Is there any elegant way to "widen" this method to be a generic method, accepting e.g. all (wrappers for) primitive types?
It would be possible to write...
public static <K extends Object, V extends Object> Map<K, V> makeMapGeneric(String theString) {
// ???
}
...but I have no idea how I would do the "castings" to the keys and values.
As far as I know, the primitive types do not have any common makeXYfromString(String ...) method, just explicit Integer.parseInt, Double.parseDouble and so on, and they do not have a common superclass/interface that I could restrict K and V to.
Giving the classes as argument (makeMapGeneric(String theString, Class<K> keyClass, Class<V> valueClass)) and writing something like K key = keyClass.cast(keyString);, isn't possible since you cannot cast a String to eg. an int, just parse it.
Is there any elegant solution possible?
I took a tought on it for a few minutes and i came up with this solution
public static <K, V> Map<K, V> makeMap(String input, Function<String, K> keyFunc, Function<String, V> valFunc) {
return Arrays.stream(input.split(";"))
.map(s -> s.split("="))
.collect(Collectors.toMap(s -> keyFunc.apply(s[0]), s -> valFunc.apply(s[1])));
}
You need to pass a two functions which will transform the string to the right value.
Use it like this:
Map<Integer, Integer> x = makeMap("123=456;321=654;89=90", Integer::parseInt, Integer::parseInt);
You could provide a Function to you method:
<K, V> Map<K, V> makeMapGeneric(String theString, Function<String, K> keyFn, Function<String, V> valueFn) {
String key = "123";
String value = "456";
K parsedKey = keyFn.apply(key);
V parsedValue = valueFn.apply(key);
}
Now you can call it with a Function that converts String to K (and V):
Map<Integer, Double> result =
makeMapGeneric("123=456", Integer::parseInt, Double::parseDouble);
What is the best way to obtain from a Map a new List with all map values??
Is this correct?
List<Value> listValues = new ArrayList<>();
for(TypeKey keys : map.keySet()){
for(TypeValue values : map.get(keys)){
listValues.add(values);
}
}
If you have a Map<Key, Value>, the Map#values() method will give you a Collection<Value>.
For a Map<Key, List<Value>>, the values() method will - obviously- give you a Collection<List<Value>> that can be flattend:
List<Value> values = map.values().stream()
.flatMap(List::stream)
.collect(Collectors.toList());
If you can not use the Java 8 Stream API, you can still make your code a bit shorter by using Map#values to iterate the values lists directly, instead of the keys, and List#addAll to add all the values to the result list at once.
public <K, V> List<V> flatValues(Map<K, List<V>> map) {
List<V> result = new ArrayList<>();
for (List<V> values : map.values()) {
result.addAll(values);
}
return result;
}
public <K, V> List<V> flatValues(Map<K, List<V>> map) {
List<V> result = new ArrayList<>();
for (List<V> values : map.values()) {
result.addAll(values);
}
return result;
}
public <K, V> List<V> flatValues(Map<K, List<V>> map) {
List<V> result = new ArrayList<>();
for (List<V> values : map.values()) {
result.addAll(values);
}
return result;
}
i have used java stream
I would like to find the biggest number in HashSet and HashMap. Say I have the number [22,6763,32,42,33] in my HashSet and I want to find the largest number in my current HashSet..how would i do this? and Same thing for the HashMap as well. I hope you can help me with it. Thank you.
You can use Collections.max(Collection) to find the maximum element out of any collection.
Similarly, for a HashMap, you can use the same method on its keySet() or values(), depending upon whether you want maximum key, or maximum value.
Also, if you want as such, you can use a TreeSet and TreeMap instead, that stores the elements in sorted key order.
try
int max = Collections.max(set);
int maxKey = Collections.max(map.keySet());
int maxValue Collections.max(map.values());
If you are forced to use a HashSet/HashMap, then you have to scan the whole HashSet/HashMap in order to find the maximum. Library functions like Collections.max() will do like this.
If you want O(1) retrieval of the maximum, and you are allowed to change the type of collection being used, use a sorted set/map (e.g. TreeSet/TreeMap).
Something like this:
Set<Integer> values = new HashSet<Integer>() {{
add(22);
add(6763);
add(32);
add(42);
add(33);
}};
int maxValue = Integer.MIN_VALUE;
for (int value : values) {
if (value > maxValue) {
maxValue = value;
}
}
And this:
Map<String, Integer> values = new HashMap<String, Integer>() {{
put("0", 22);
put("1", 6763);
put("2", 32);
put("3", 42);
put("4", 33);
}};
int maxValue = Integer.MIN_VALUE;
for (int value : values.values()) {
if (value > maxValue) {
maxValue = value;
}
}
In case of TreeMap, if you know the key/values are inserted randomly, the tree will be more or less balanced. Trees become unbalanced, if data is inserted in already sorted order, the capability to quickly find (or insert or delete) a given element is lost. In case of unbalanced tree, it will take time proportional to n, O(n) else O(1).
Consider using Apache Commons Math. Here is the API docs.
The class of interest is SummaryStatistics. It works with doubles and computes max, min, mean etc. on the fly (as you add values to it). The data values are not stored in memory, so this class can be used to compute statistics for very large data streams.
Here is a simple method which does what you are asking:
public String getMapKeyWithHighestValue(HashMap<String, Integer> map) {
String keyWithHighestVal = "";
// getting the maximum value in the Hashmap
int maxValueInMap = (Collections.max(map.values()));
//iterate through the map to get the key that corresponds to the maximum value in the Hashmap
for (Map.Entry<String, Integer> entry : map.entrySet()) { // Iterate through hashmap
if (entry.getValue() == maxValueInMap) {
keyWithHighestVal = entry.getKey(); // this is the key which has the max value
}
}
return keyWithHighestVal;
}
Note : If you want to find the biggest value from Map try maxEntry.get().getValue() instead of maxEntry.get().getKey()
1. Using Stream
public <K, V extends Comparable<V>> V maxUsingStreamAndLambda(Map<K, V> map) {
Optional<Entry<K, V>> maxEntry = map.entrySet()
.stream()
.max((Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
.compareTo(e2.getValue())
);
return maxEntry.get().getKey();
}
2. Using Collections.max() with a Lambda Expression
public <K, V extends Comparable<V>> V maxUsingCollectionsMaxAndLambda(Map<K, V> map) {
Entry<K, V> maxEntry = Collections.max(map.entrySet(), (Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue()
.compareTo(e2.getValue()));
return maxEntry.getKey();
}
3. Using Stream with Method Reference
public <K, V extends Comparable<V>> V maxUsingStreamAndMethodReference(Map<K, V> map) {
Optional<Entry<K, V>> maxEntry = map.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getValue));
return maxEntry.get()
.getKey();
}
4. Using Collections.max()
public <K, V extends Comparable<V>> V maxUsingCollectionsMax(Map<K, V> map) {
Entry<K, V> maxEntry = Collections.max(map.entrySet(), new Comparator<Entry<K, V>>() {
public int compare(Entry<K, V> e1, Entry<K, V> e2) {
return e1.getValue()
.compareTo(e2.getValue());
}
});
return maxEntry.getKey();
}
5. Using Simple Iteration
public <K, V extends Comparable<V>> V maxUsingIteration(Map<K, V> map) {
Map.Entry<K, V> maxEntry = null;
for (Map.Entry<K, V> entry : map.entrySet()) {
if (maxEntry == null || entry.getValue()
.compareTo(maxEntry.getValue()) > 0) {
maxEntry = entry;
}
}
return maxEntry.getKey();
}
I have a function which returns a one-sided intersection of values between two input maps:
Map<Key, Value> mergeMaps(Map aKeys<CompositeKey, Key>,
Map <CompositeKey, Value> aValues) {
Map<Key, Value> myResult = Maps.newHashMap();
for (CompositeKey myKey : aKeys.keySet()) {
if (aValues.containsKey(myKey)) {
myResult.put( aKeys.get(myKey), aValues.get(myKey));
}
}
return myResult;
}
This is not a transitive mapping composition i.e.
T->K, K->V ===> T->V
but instead transforming
T->(K,V) ===> K->V
Is there a way in Java to make this function generic such that its signature is as follows?
Map<K, V> mergeMaps(Map aKeys<T, K>, Map <T, V> aValues)
I think this signature should do what you want:
<T, K, V> Map<K, V> mergeMaps(Map<T, K> aKeys, Map<T, V> aValues)
For a completely generic form you can have
public <T, K, V> Map<K, V> mergeMaps(Map<T, K> aKeys, Map<T, V> aValues)
If K and V are set in the class you can take them out.
For a case where you want to specify a relation between T and K, V you might want something
like
public <K, V, T extends CompositeKey<K, V>> ...
possibly with some ? extends or ? super in there, but it depends a bit on the use case.