Data Structure Set, List, Map or Tree? - java

I am trying to choose a Java data structure with the following properties
Key: Long
Value: Set
Is there a structure that I can index into and add values to the Set?
For example say I have the object <1, [a,b,c]> and I want to add d this so that the output is <1, [a,b,c,d]>?
Can this be easily done in java?

If you are able to use a third party library, Guava has Multimaps, which make it easy to store multiple values for a single key.
For example:
import com.google.common.collect.HashMultimap;
HashMultimap<Long, String> multimap = HashMultimap.create();
multimap.put(1L, "a");
multimap.put(1L, "b");
multimap.put(1L, "c");
multimap.put(1L, "d");
See the docs.

As others have stated, you will be best served by a Map<Long, Set<String>>. In your example:
Map<Long, Set<String>> myMap = new HashMap<Long, Set<String>>();
Set<String> initialSet = new HashSet<String>();
initialSet.add("a");
initialSet.add("b");
initialSet.add("c");
myMap.put(1, initialSet);
myMap.get(1).add("d"); // to add the "d"

I have the object <1, [a,b,c]> and I want to add d this so that the output is <1, [a,b,c,d]>?
Map<Long, Set<Character>
would work good

Yes a Map would work.
Map yourmap = new HashMap<Long, List<String>>();

Just use:
HashMap<Long, String> map = new HashMap<Long, ArrayList<String>>();
If you want to add something to it just
ArrayList<String> list = map.get(KEY_YOU_WANT_TO_CHECK);
if(list == null){
list = new ArrayList<String>();
list.add(STRING_YOU_WANT_TO_ADD);
map.put(KEY_YOU_WANT_TO_CHECK,list);
}else{
list.add(STRING_YOU_WANT_TO_ADD);
}
Of course you can replace ArrayList with HashSet also with Vector and TreeSet

Related

Copy one HashMap<K,V> to another HashMap<V,K> in O(1) complexity (JAVA)

Suppose I have a HashMap<String,String> which have elements {one=1, two=2, three=3, four=4} and I want to create another HashMap<String,String> whose elements would be {1=one, 2=two, 3=three, 4=four}
One approach is
HashMap<String,String> map1 = new HashMap<String,String>();
map1.put("one",1);
map1.put("two",2);
map1.put("three",3);
map1.put("four",4);
HashMap<String,String> map2 = new HashMap<String,String>();
for(String s : map.keySet())
{
map2.put(map.get(s),s);
}
But it has time complexity O(N)
I want to know is there any way to do this in O(1)
You seem to be after a bidirectional map. Java does not have such datastructure in its core library.
But Google Guava library has BiMap, which seems to be what you want:
BiMap<String, String> biMap = HashBiMap.create();
biMap.put("key1", "value1");
biMap.put("key2", "value2");
BiMap<String, String> inverse = biMap.inverse();
String key1 = inverse.get("value1"); // key1
Here the BiMap.inverse() method returns a view of the original map. This is a O(1) time complexity operation.
Totally agree with #andreas, it isn't possible with HashMap.
You might want to use BitMap as suggested by #fps but if have to do it with HashMap you don't really have many options.
Here is how to invert a HashMap with streams API:
Map<String,String> map = Map.of("one","1","two","2","three","3")
Map<String,String> reversedMap = map.entrySet()
.stream()
.map(es -> Map.entry(es.getValue(),es.getKey()))
.collect(Collectors.toMap(es -> es.getKey(), es->es.getValue()));

java insert in Map<String, Set<String>>

In C++ I can do:
map<string, set<string>> v;
v["AHA"].insert("BA");
In java I have:
HashMap<String, Set<String>> v = new HashMap<String, Set<String>>();
How I can insert "BA" to v["AHA"] as some as c++?
Yes I try this:
Set<String> vs = V.get("B");
if (vs == null) vs = new HashSet<String>();
vs.add("V");
V.put("B", vs);
but is large
If you want to add something into the set, and allow for the possibility that the key/value pair might not yet exist in the map, you can use computeIfAbsent
v.computeIfAbsent("AHA", k -> new HashSet<String>()).add("BA")
This will look up the key in the map, and if it is missing, add it with a new empty set as the value, so you can then add stuff straight into it.
If you're using a version of Java before Java 8, it's a little more code:
Set<String> s = v.get("AHA");
if (s==null) {
s = new HashSet<String>();
v.put("AHA", s);
}
s.add("BA");
HashMap<String, Set<String>> v = new HashMap<String, Set<String>>();
Set<String> set = new HashSet<String>();
set.add("some data");
v.put("AHA",set);
Create a Set first and then store it in Map.

Convert ArrayList to HashMap<String, String>

I have this ArrayList
public ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
and I want to convert this to:
HashMap<String, String> comparemap2 = new HashMap<>();
What I want is: I want all the Items inside the ArrayList and want to put them into the HashMap
My HashMap looks like:
KEY VALUE
job_id 032014091029309130921.xml
job_id 201302149014021492929.xml
job_id 203921904901920952099.xml
EDIT:
Later I want to compare this map with an existing map:
Properties properties = new Properties();
try {
properties.load(openFileInput("comparexml.kx_todo"));
} catch (IOException e) {
e.printStackTrace();
}
for (String key : properties.stringPropertyNames()) {
compareMap.put(key, properties.get(key).toString());
}
HashMap<String, String> oldCompareMap = new HashMap<>();
for (HashMap key : xmlFileNames) {
oldCompareMap.putAll(key);
}
isEqualMaps(oldCompareMap, compareMap);
I only want to compare, if the filename exists in the compareMap. If not, than add it to the xmlFileName Map
I've looked up in StackOverFlow, how I can convert ArrayList to HashMap. But the other Threads treat data types like Item or Product.
I hope you can help me!
Kind Regards
Given...
public ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
then something like this should do it.
HashMap<String, String> nhm = new HashMap<>();
for (HashMap xmlFileHm : xmlFileNames ) {
nhm.putAll(xmlFileHm);
}
but be aware if you have duplicate keys in your hashmaps they will get overwritten.
You should also think about coding to interfaces. Take a look at Map and List rather than typing your collections to implementations (ArrayList and HashMap). Take a look at this thread which is quite interesting What does it mean to "program to an interface"?
Depending on what you are trying to do as well you might consider a MultiMap as this might server your purposes better
Edit After update to the question...
A multimap would be better here with one key and multiple values. Although arguably if the key never changes then you could just store the values in a list. For multiamps you can use Google's guava library or do one yourself. For example (not checked for compilation errors as Im doing this from my head)
Map<String, List<String>> m = new HashMap<>();
if (m.containsKey("key")) {
m.get("key").add("new value");
}
else {
List<String> l = new ArrayList<>();
l.add("new value");
m.put("key", l);
}
You can create a new HashMap, then iterate through the list and put all elements from the map from the list to the main map.
List<Map<String, String>> list = new ArrayList<>();
Map<String, String> map = new HashMap<>();
for (Map<String, String> mapFromList : list) {
map.putAll(mapFromList);
}
You can try something like this..
ArrayList<HashMap<String, String>> xmlFileNames = new ArrayList<>();
HashMap<String, String> comparemap2 = new HashMap<>();
for(HashMap<String, String> i:xmlFileNames){
comparemap2.putAll(i);
}
You may need to consider the case of duplicate keys. else they will get override.
Create a new map and put All each element of arrayList to the map.
But in that case if you have same keys in two element of arrayList (hashmap) then it will override the previous one.

Hashmap value getting updated in all keys

I am having map like this
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
map---> {A=[], B=[], C=[]}
I am trying to add "hai" to key A.
But it is getting added to all key. Below is my code
I am wrong somewhere
for (Entry<String, List<String>> entry : map.entrySet()) {
String a = entry.getKey();
if(a.equals(attr)){
List<String> temp = entry.getValue();
temp.add("hai");
map.put(a, temp);
System.out.println("----------"+map);
}
}
output: ------------{A=[hai], B=[hai], C=[hai]}
please suggest
Thanks in advance
Not sure why that's happening, maybe as Eran suggested it's in code you aren't showing. However, there's a much easier way to do this instead of iterating through all the keys...
Map<String, List<String>> map = new HashMap<>();
...
List<String> values = map.get(attr);
if(values == null) {
values = new ArrayList<String>();
map.put(attr, values);
}
values.add("hai");
And I'm just guessing here, but I suspect you are doing this to create the array in the first place...
Map<String, List<String>> map = new HashMap<>();
List<String> values = new ArrayList<>();
map.put("A", values);
map.put("B", values);
map.put("C", values);
This causes A, B, and C to all share the same instance of the List. Therefore when you manipulate the list under one key (say, A), you are really making the same change to the lists stored under all keys, because it is the SAME list for all three.
The fix for that is described above, but essentially you want to create a new instance of List for each key in the map.
You are probably putting the same List in all the values of the Map. However, that happens in code you didn't show. When you put a key in the Map for the first time, make sure you are creating a new List for its value.

Creating Map using put() method

I am trying to create a dictionnary in a <K, List<V>> format.
private static Map<String, Collection<String>> dict = new HashMap<String, Collection<String>>();
Using new HashMap<>(); or new HashMap<String, ArrayList<String>>(); throws incompatible data types error
I need a dictionary similar to the one below.
a: apple, ajar, axe, azure
b: ball, bat, box
d: dam, door, dish, drown, deer, dare
u: urn, umbrella
y: yolk
To do this, I worte below code. put() returns incompatible paramters compilation error. What is the right way to use put() for this example?
dict.put("a", "apple");
dict.put("a", "ajar");
.
.
.
dict.put("u", "umbrella");
dict.put("y", "yolk");
You need to place a List as the value to the map, for example:
List<String> listA = Arrays.asList("apple", "ajar", "axe", "azure");
dict.put("a", listA);
Alternatively, you can use guava Multimap which allows more than one value to be mapped to a given key.
This is because you need to put an arrayList in the value as your Map declaration is Map<String, Collection<String>> so it cannot take Map<String, String>.
ArrayList<String> list = new ArrayList<String>();
list.add("apple");
dict.put("a",list );
As per java 7 you can do it using diamond operator so you can create a map as,
List<String, List<String>> = new ArrayList<>();
What you need is this;
List al = new ArrayList<String>();
al.add("apple");
al.add("ajar");
HashMap<String, List<String>> hm = new HashMap<String, List<String>>();
hm.put("a", al);
System.out.println(hm.get("a"));
This is because, when you use;
private static Map<String, Collection<String>>
You need a Collection like a List. DoNOT insert Objects as Strings
You can only follow the definition you have done :
Map<String, Collection<String>> implies you use dict.put(a,b) with a being a String and b a Collection.
You're trying to put a String as a value that's your problem.
You may want to do something like that :
Collection col = dict.get("a");
if (col == null) {
col = new ArrayList();
}
col.add("apple");
dict.put("a",col);
I would first change the type of the dictionary to
private static Map<Character, ArrayList<String>> dict = new HashMap<>();
It'll allow easier putting of array lists as generics are not covariant.
For each letter, create:
ArrayList<String> myList=new ArrayList<>();
and put() it to dict with
dict.put(myList);
Then you can add words with:
dict.get(letter).put(word);
Your exact need is MultiMap feature of apache-commons
MultiMap dict = new MultiHashMap();
dict.put("a", "apple");
dict.put("a", "ajar");
.
.
.
dict.put("u", "umbrella");
dict.put("y", "yolk");

Categories

Resources