I have a Map and a HashSet.
The goal is to check the contents of the Set against the Map and add it to the Map if the elements are there in the HashSet but not in the Map.
// Map is defined in a class
private final Map<String, A> sb = new ConcurrentHashMap<>();
public void someMethod() {
Set<A> hSet = new HashSet<>();
for (A a : ab){
hSet.add(a..a...);
// Check if all elements added to hash Set are there in a Map
// if not present, add it to Map
}
}
if you want to search in map values:
if(!map.values().contains(a))
// put a in the map
if you want to look for keys
if(!map.containsKey(a))
// put a in the map
keep in mind that contains calls equals so in your A class you have to implement hashCode and equals.
public static void main(String[] args) {
Set<String> set = Stream.of("a","b","c","d").collect(Collectors.toSet());
Map<String, String> map = new HashMap<String, String>();
map.put("a", "foo");
map.put("h", "bar");
map.put("c", "ipsum");
for (String string : set) {
if(!map.containsKey(string)) {
map.put(string,string);
}
}
System.out.println(map);
}
output
{a=foo, b=b, c=ipsum, d=d, h=bar}
for (String element : hSet) {
if (!sb.containsKey(element)) {
sb.put(element, A);
}
}
Following could also be solution:
private final Map<String, A> sb = new ConcurrentHashMap<>();
public void someMethod() {
Set<String> set = new HashSet<>();
set.stream().filter(word -> !sb.containsKey(word))
.forEach(word -> sb.put(word, correspondingValueOfTypeA));
}
Related
Declaration:-
private static HashMap<String, HashMap<String, ArrayList>> parentMap = new HashMap<>();
private static HashMap<String, ArrayList> childMap = new HashMap<>();
How do I want to store data in hashmap?
"India":
"EmployeeName":[A,B,C]
"China":
"EmployeeName":[D,E,F]
Methods used:-
public static ArrayList<String> getMap(String parentkey, String childKey) {
return parentMap.get(parentkey).get(childKey);
}
public static ArrayList<String> setMap(String parentkey, String childKey, String value) {
childMap.computeIfAbsent(childKey, k -> new ArrayList<>()).add(value);
parentMap.put(parentkey, childMap);
return getMap(parentkey, childKey);
}
setMap("India", "EmployeeName", "A")
setMap("India", "EmployeeName", "B")
setMap("India", "EmployeeName", "C")
setMap("China", "EmployeeName", "D")
setMap("China", "EmployeeName", "E")
setMap("China", "EmployeeName", "F")
How data get stored and printed in hashmap while fetchng from getMap method:
System.out.println("India" + getMap("India").get("EmployeeName"));
System.out.println("China" + getMap("China").get("EmployeeName"));
"India" [A,B,C,D,E,F]
"China" [A,B,C,D,E,F]
Whilst i know keeping the childKey name unique would do thejob for me but I wish to keep the same childKey name under each parentkey name and store the respecive value in arraylist.
Any solution to my problem is welcome.
The problem is that you keep reusing the same childMap, regardless of which parentKey is being used. You need to look up the respective child map when adding values.
That means that childMap should be a local variable, nothing more. Delete your private static HashMap<String, ArrayList> childMap.
Try this:
public static ArrayList<String> setMap(String parentkey, String childKey, String value) {
HashMap<String, ArrayList> childMap = parentMap.computeIfAbsent(parentkey, k->new HashMap<>());
childMap.computeIfAbsent(childKey, k -> new ArrayList<>()).add(value);
return getMap(parentkey, childKey);
}
Proof that this works
Suggestion, don't have generic types and dont have static params
private HashMap<String, HashMap<String, ArrayList<String>>> parentMap = new HashMap<>();
private HashMap<String, ArrayList<String>> childMap = new HashMap<>();
Try to replace this method
public ArrayList<String> setMap(String parentkey, String childKey, String value) {
childMap.putIfAbsent(childKey, new ArrayList<>()); // inserts a key only if the key is not already present
childMap.get(childKey).add(value); // puts the value in the existing key and
if (!parentMap.containsKey(parentkey)) { // puts in the parent map only if not present.
parentMap.put(parentkey, childMap);
}
}
Since the childmap is referenced already, No need to put again.
If I was you I will do it in more "OOP way" so that you can benefit from static typing. Something like:
import java.util.List;
class Employee{
String name;
String getName(){
return name;
}
}
public class CompanyBranch{
String national;
List<Employee> employees;
List<String> getEmployeeAllName(){
return employees.stream().map(Employee::getName).toList();
}
}
I have two java classes:
public class MyClass1 {
private String userId;
private String userName;
private List<CustomList1> customList1;
// getters and setters
// inner CustomList1 class
}
public class MyClass2 {
private String userId;
private List<CustomList2> customList2;
// getters and setters
// inner CustomList2 class
}
Now, I have have lists of these classes:
List<MyClass1> classOneList;
List<MyClass2> classTwoList;
In both classOneList and classTwoList lists, object should be sorted with userId ascending. userId in both lists should have same values. What I want to check is that:
Has both lists same size? If not, thow error exception about.
Has every next element from both list the same userId? If not, throw another exception.
Step 1. I have done with simply if statement.
By prototype, step 2. should look like this:
for (el1, el2 : classOneList, classTwoList) {
el1.getUserId().isEqualTo(el2.getUserId());
}
Try the below code for your problem.
public class Testing {
public static void main(String[] args) {
Map<String, List<String>> map1 = new LinkedHashMap<String, List<String>>();
List<String> m1l1 = new LinkedList<String>();
m1l1.add("One");
m1l1.add("Two");
m1l1.add("Three");
m1l1.add("Four");
map1.put("1", m1l1);
List<String> m1l2 = new LinkedList<String>();
m1l2.add("One");
m1l2.add("Two");
m1l2.add("Three");
m1l2.add("Four");
map1.put("2", m1l2);
// Add more element into the map1 by creating more list.
Map<String, List<String>> map2 = new LinkedHashMap<String, List<String>>();
List<String> m2l1 = new LinkedList<String>();
m2l1.add("One");
m2l1.add("Two");
m2l1.add("Three");
m2l1.add("Four");
map2.put("1", m2l1);
// Add more element into the map2 by creating more list.
for (Entry<String, List<String>> entry : map1.entrySet()) {
if (map2.containsKey(entry.getKey())) {
if (entry.getValue().size() == map2.get(entry.getKey()).size()) {
} else {
System.out.println("UserId are same but list are different for userid: " + entry.getKey());
}
}
else {
System.out.println("Userid '"+entry.getKey()+"' exists in map1 but is not found in map2");
}
}
}
}
Hope this may help you.
if(classOneList.size() != classTwoList.size()){
throw new ErrorException();
}else{
classOneList = classOneList.stream().sorted(Comparator.comparing(MyClass1::getUserId)).collect(Collectors.toList());
classTwoList = classTwoList.stream().sorted(Comparator.comparing(MyClass2::getUserId)).collect(Collectors.toList());
for (int i = 0; i < classOneList.size(); i++){
if(!classOneList.get(i).getUserId().equals(classTwoList.get(i).getUserId())){
throw new AnotherErrorException();
}
}
}
Given a Map<String, Object>, where the values are either a String or another Map<String, Object>, how would one, using Java 8, flatten the maps to a single list of values?
Example:
Map - "key1" -> "value1"
- "key2" -> "value2"
- "key3" -> Map - "key3.1" -> "value3.1"
- "key3.2" -> "value3.2"
- "key3.3" -> Map - "key3.3.1" -> "value3.3.1"
- "key3.3.2" -> "value3.3.2"
For the above example, I would like the following list:
value1
value2
value3.1
value3.2
value3.3.1
value3.3.2
I know it can be done like this:
public static void main(String args[]) throws Exception {
//Map with nested maps with nested maps with nested maps with nested......
Map<String, Object> map = getSomeMapWithNestedMaps();
List<Object> values = new ArrayList<>();
addToList(map, values);
for (Object o:values) {
System.out.println(o);
}
}
static void addToList(Map<String, Object>map, List<Object> list) {
for (Object o:map.values()) {
if (o instanceof Map) {
addToList((Map<String, Object>)o, list);
} else {
list.add(o);
}
}
}
How can I do this with a Stream?
Edit:
After some playing around I figured it out:
public static void main(String args[]) throws Exception {
//Map with nested maps with nested maps with nested maps with nested......
Map<String, Object> map = getSomeMapWithNestedMaps();
//Recursively flatten maps and print out all values
List<Object> list= flatten(map.values().stream()).collect(Collectors.toList());
}
static Stream<Object> flatten(Stream<Object> stream) {
return stream.flatMap((o) ->
(o instanceof Map) ? flatten(((Map<String, Object>)o).values().stream()) : Stream.of(o)
);
}
You could define a recursive method which flattens one map and use it as a function for Stream#flatMap or use it by calling it directly.
Example:
public class FlatMap {
public static Stream<Object> flatten(Object o) {
if (o instanceof Map<?, ?>) {
return ((Map<?, ?>) o).values().stream().flatMap(FlatMap::flatten);
}
return Stream.of(o);
}
public static void main(String[] args) {
Map<String, Object> map0 = new TreeMap<>();
map0.put("key1", "value1");
map0.put("key2", "value2");
Map<String, Object> map1 = new TreeMap<>();
map0.put("key3", map1);
map1.put("key3.1", "value3.1");
map1.put("key3.2", "value3.2");
Map<String, Object> map2 = new TreeMap<>();
map1.put("key3.3", map2);
map2.put("key3.3.1", "value3.3.1");
map2.put("key3.3.2", "value3.3.2");
List<Object> collect = map0.values().stream()
.flatMap(FlatMap::flatten)
.collect(Collectors.toList());
// or
List<Object> collect2 = flatten(map0).collect(Collectors.toList());
System.out.println(collect);
}
}
For the given nested map, it prints
[value1, value2, value3.1, value3.2, value3.3.1, value3.3.2]
I am new to hash mapping and I was trying to created a nested hash map on one side of the class and create another class to call it out, so here's how my code looks like
public class Hash {
private HashMap<String, HashMap<String, String>> wow = new HashMap<String, HashMap<String, String>>();
public void SetHash(){
wow.put("key", new HashMap<String, Object>());
wow.get("key").put("key2", "val2");
}
public HashMap GetMap(){
return wow;
}
}
And on the other class which is the main class it will be like this:
public static void main(String[] args) {
Hash h = new Hash();
h.SetHash();
System.out.println(h.GetMap.get("key").get("key2"));
}
But when I place the second get, there's an error, so I am not sure if this is possible or if I should actually place the hash directly at the main class.
GetMap is a method, not an attribute, so you have to refer it with parenthesis ():
h.GetMap().get("key")
Now, second error. Your Map<String, Map<String, String> named wow contains a values that are objects of the type Map<String, String> so, before the get, you need get the map:
Map<String, String> m = (HashMap<String, String>) h.GetMap().get("key");
And then you can print it:
System.out.println(m.get("key2"));
if you want an ONELINER (is not really clear, but check explanation in comments):
System.out.println(((HashMap<String, String>) h.GetMap().get("key")).get("key2"));
// ↑ casting parenthesis ↑ (
// ↑ this say group IS a map and allow get() ↑
// ↑ system.out.println parenthesis ↑
NOTE: change also this declaration
wow.put("key", new HashMap<String, Object>());
By
wow.put("key", new HashMap<String, String>());
FINAL CODE:
public class Q37066776 {
public static void main(String[] args) {
Hash h = new Hash();
h.SetHash();
Map<String, String> m = (HashMap<String, String>) h.GetMap().get("key");
System.out.println(m.get("key2"));
}
}
class Hash {
private HashMap<String, HashMap<String, String>> wow = new HashMap<String, HashMap<String, String>>();
public void SetHash() {
wow.put("key", new HashMap<String, String>());
wow.get("key").put("key2", "val2");
}
public HashMap GetMap() {
return wow;
}
}
WORKING ONLINE DEMO
but you can always
Do it better! :=)
As pointed by Andrew
you can change return of the method,
But also many other things like:
using less concrete objects (Map instead of HashMap)
follow conventions (GetMap() would be getMap())
Make Hash a static class with static block
If I had to rewrite your code, my result would be like this:
public class Q37066776 {
public static void main(String[] args) {
System.out.println(Hash.getMap().get("key").get("key2"));
}
}
class Hash {
private static Map<String, Map<String, String>> wow = new HashMap<String, Map<String, String>>();
static {
wow.put("key", new HashMap<String, String>());
wow.get("key").put("key2", "val2");
}
public static Map<String, Map<String, String>> getMap() {
return wow;
}
}
You have 3 errors:
GetMap is a method - you need to write GetMap().
you declared the inner Map as HashMap<String, String> - you cannot initialize the inner map to: wow.put("key", new HashMap<String, Object>());
Change it to wow.put("key", new HashMap<String, String>());
In order to access the inner map from the main - you must declare the returned value of GetMap to be Map<String, HashMap<String, String>> instead of just raw type. Otherwise, the outer class won't know that the outer map value is also a hash map.
Instead of using nested maps, you should use google's Guava Table:
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Table.html
It may be a bad practice, but I haven't been able to figure out any better solution for my problem. So I have this map
// Map<state, Map<transition, Map<property, value>>>
private Map<String, Map<String, Map<String, String>>> properties;
and I want to initialize it so I don't get NullPointerException with this
properties.get("a").get("b").get("c");
I tried this one but I didn't work (obviously)
properties = new HashMap<String, Map<String, Map<String,String>>>();
Other things I tried didn't compile.
Also if you have any ideas how to avoid this nested maps, I would appreciate it.
It seems to me that you need to create your own Key class:
public class Key {
private final String a;
private final String b;
private final String c;
public Key(String a, String b, String c) {
// initialize all fields here
}
// you need to implement equals and hashcode. Eclipse and IntelliJ can do that for you
}
If you implement your own key class, your map will look like this:
Map<Key, String> map = new HashMap<Key, String>();
And when looking for something in the map you can use:
map.get(new Key("a", "b", "c"));
The method above will not throw a NullPointerException.
Please remember that for this solution to work, you need to override equals and hashcode in the Key class. There is help here. If you don't override equals and hashcode, then a new key with the same elements won't match an existing key in the map.
There are other possible solutions but implementing your own key is a pretty clean one in my opinion. If you don't want to use the constructor you can initialize your key with a static method and use something like:
Key.build(a, b, c)
It is up to you.
You need to put maps in your maps in your map. Literally:
properties = new HashMap<String, Map<String, Map<String,String>>>();
properties.put("a", new HashMap<String, Map<String,String>>());
properites.get("a").put("b", new HashMap<String,String>());
If your target is lazy initialization without NPE you have to create your own map:
private static abstract class MyMap<K, V> extends HashMap<K, V> {
#Override
public V get(Object key) {
V val = super.get(key);
if (val == null && key instanceof K) {
put((K)key, val = create());
}
return val;
}
protected abstract V create();
}
public void initialize() {
properties = new MyMap<String, Map<String, Map<String, String>>>() {
#Override
protected Map<String, Map<String, String>> create() {
return new MyMap<String, Map<String, String>>() {
#Override
protected Map<String, String> create() {
return new HashMap<String, String>();
}
};
}
};
}
You could use a utility method:
public static <T> T get(Map<?, ?> properties, Object... keys) {
Map<?, ?> nestedMap = properties;
for (int i = 0; i < keys.length; i++) {
if (i == keys.length - 1) {
#SuppressWarnings("unchecked")
T value = (T) nestedMap.get(keys[i]);
return value;
} else {
nestedMap = (Map<?, ?>) nestedMap.get(keys[i]);
if(nestedMap == null) {
return null;
}
}
}
return null;
}
This can be invoked like this:
String result = get(properties, "a", "b", "c");
Note that care is required when using this as it is not type-safe.
The only way to do it with this structure is to pre-initialise the 1st and 2nd level maps with ALL possible keys. If this is not possible to do you can't achieve what you are asking with plain Maps.
As an alternative you can build a custom data structure that is more forgiving. For example a common trick is for a failed key lookup to return an "empty" structure rather than null, allowing nested access.
You can't initialize this in one go, since you normally don't know what keys you'll have in advance.
Thus you'd have to check whether the submap for a key is null and if so you might add an empty map for that. Preferably you'd only do that when adding entries to the map and upon retrieving entries you return null if one of the submaps in the path doesn't exist. You could wrap that in your own map implementation for ease of use.
As an alternative, apache commons collections' MultiKeyMap might provide what you want.
It's impossible to use properties.get("a").get("b").get("c"); and be sure to avoid null unless you make your own Map. In fact, you can't predict that your map will contains "b" key.
So try to make your own class to handle nested get.
I think a better solution is using an object as the only key to the map of values. The key will be composed of three fields, state, transition and property.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Key {
private String state;
private String transition;
private String property;
public Key(String state, String transition, String property) {
this.state = state;
this.transition = transition;
this.property = property;
}
#Override
public boolean equals(Object other) {
return EqualsBuilder.reflectionEquals(this, other);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
When you check for a value, the map will return null for a key that is not associated with a value
Map<Key, String> values = new HashMap<Key, String>();
assert values.get(new Key("a", "b", "c")) == null;
values.put(new Key("a", "b", "c"), "value");
assert values.get(new Key("a", "b", "c")) != null;
assert values.get(new Key("a", "b", "c")).equals("value");
To efficiently and correctly use an object as a key in a Map you should override the methods equals() and hashCode(). I have built thos methods using the reflective functionalities of the Commons Lang library.
I think, following is the easier way:
public static final Map<Integer, Map<Integer, Map<Integer, Double>>> A_Map = new HashMap<Integer, Map<Integer, Map<Integer, Double>>>()
{
{
put(0, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 60.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 160.0);
put(1, 1 / 13600.0);
}
});
}
});
put(1, new HashMap<Integer, Map<Integer, Double>>()
{
{
put(0, new HashMap<Integer, Double>()
{
{
put(0, 1 / 260.0);
put(1, 1 / 3600.0);
}
});
put(1, new HashMap<Integer, Double>()
{
{
put(0, 1 / 560.0);
put(1, 1 / 1300.0);
}
});
}
});
}
};
Using computeIfAbsent/putIfAbsent makes it simple:
private <T> void addValueToMap(String keyA, String keyB, String keyC, String value) {
map.computeIfAbsent(keyA, k -> new HashMap<>())
.computeIfAbsent(keyB, k -> new HashMap<>())
.putIfAbsent(keyC, value);
}