hashmap and arraylist connected - java

My main purpose is to make my arraylist and hashmap always connected.
Connected in the sense means if I add any thing in map then it should be copied in ArrayList and viceversa.
Any idea guys.
static Map<Integer,Employee> emp = new HashMap<Integer,Person>();
static ArrayList<Employee> ls = new ArrayList <Employee>(emp.values());
by this code whatever I add in HashMap is getting copied in list,but when I remove from ArrayList it's not reflecting in map.
pls help.

Just use the emp.values() collection. It is backed up by the map and vice-verca. See http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#values()
Collection<Employee> ls = emp.values();
If you remove something from this Collection, it will be removed from the HashMap as well.
In your example you are creating a new ArrayList and copying the reference of all elements into it. Of course this new ArrayList has no idea of you HashMap.
A short example:
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
// Output is "{1=One, 2=Two, 3=Three}"
System.out.println(map);
Collection<String> backedUpCollection = map.values();
// Remove something from collection and check the maps content
backedUpCollection.remove("Two");
// Output is "{1=One, 3=Three}"; "Two" was removed
System.out.println(map);
// Add an entry to the map and check the content of collection
map.put(4, "Four");
// Output is "[One, Three, Four]"; "Four" was added
System.out.println(backedUpCollection);

You say:
Connected in the sense means if I add any thing in map then it should be copied in ArrayList and viceversa.
But lets say that you add something to the array list, what would you want the key to be for the hash map?
Once you decide on the behavior for each use case, the solution that I suggest is to write your own add and delete functions, which always add/remove values from both the array and the hash. Then you can use those methods, which wrap around the methods provided by Java, instead of using them directly.

Related

Best way to check a list of values present in a map

I have a Collection containing some values.
Collection<String> myList = new ArrayList<String>();
myList.add("a");
myList.add("b");
myList.add("c");
I created a Map which has some values:
Map<String, String> myMap = new HashMap<String, String>();
myMap.put("r", "r");
myMap.put("s","m");
myMap.put("t", "n");
myMap.put("a", "o");
I want to check whether the values in the list are present as a key in the map? The way which I know using Java is to iterate through the list and check if the map contains that particular value using myMap.containsKey(). I want to know if there is anything out there using streams or for-each which saves me either lines of code or an efficient way of doing that! Thanks for thinking through it.
EDIT:
I want to store all the elements present in the myList which are not there in myMap. So my output can be a list e.g in this scenario [b,c].
Set<String> mySet = new HashSet<String>(myList);
myMap.keySet().containsAll(set);
Does this answer your question?
After your EDIT: Given the above, you can get the keys difference between two sets using the answer to one of these questions:- What is the best way get the symmetric difference between two sets in java? or Getting the difference between two sets
...whether the values in the list are present as a key in the map?
As I understand this case as you need to verify whether all the elements in the myList are present as the myMap's keys. Use the Stream::allMatch method:
myMap.keySet().stream()
.allMatch(myList::contains);
... which is the same as:
myList.keySet().containsAll(myMap);
EDIT: I want to store all the elements present in the myList which are not there in myMap. So my output can be a list e.g in this scenario [b,c].
You don't want to store all the elements in the myList since they are already there filled. You want to retain those elements using List::retainAll.
myList.retainAll(myMap.keySet());
Printing out the result of myList would produce only the keys, that have been found in the original myList and also as a key of myMap.
Using Streams you can do something like:
List<String> result = myList.stream()
.filter(myMap::containsKey)
.collect(Collectors.toList());
The resulting list will contain the values that are present as key in the map.
In case you want to print them out you can do:
result.forEach(System.out::println);
For: I want to store all the elements present in the myList which are
not there in myMap. So my output can be a list e.g in this scenario
[b,c]
Create a duplicate myList and remove all myMap's keys
Collection<String> newList = new ArrayList<>(myList);
newList.removeAll(myMap.keySet());
System.out.println(newList);

Quick way to search through arrayList

I have an arraylist Arraylist<String[]> and I am trying to find a quick way of looking for a specific value on a specific index of the String[]. My ArrayList is always going to contain String[] of length 2. And what I want to do is look through the ArrayList for any String[] that has a specific value i.e. str[1]="value". I know that I can iterate through the ArrayList taking every single element (String[]) and then looking for the value using str[1].equals("value") but I was wondering if there is a quicker way of doing it by maybe using contains() of the ArrayList or something.
thanks
PS: I don't know the value of the first element of my array (str[0]) so I cannot construct a new String[] and check if the ArrayList contains that
If you look into ArrrayList#contains - you will see, that this method also iterates through all elements.
You could use a parallelStream - so that the ArrayList can be searched by more threads.
List<String[]> listToSearchIn = new ArrayList<String[]>();
List<String[]> matches = listToSearchIn.parallelStream()
.filter((element) -> element[1].equals("value"))
.collect(Collectors.toList());
LinkedHashMap
How about using a LinkedHashMap<String, String[]> instead of the ArrayList? The key would be the String[1] value. Linked because that gives you predictable iteration order.
An auxiliary Map
Or you could create a Map<String, Integer> where the key is the String[1] value and the value is the index of your String[] in the ArrayList.
ArrayList<String[]> al = new ArrayList<>();
Map<String, Integer> alIndexMap = new HashMap<>();
// ...
Integer nextIndex = al.size();
al.add(someStringArray);
alIndexMap.put(someStringArray[1], nextIndex);
If you keep al and alIndexMap in sync all the time, you'll always know where in al is the array that you're looking for.
Guava BiMap
Google's Guava has some classes that implement their BiMap interface. It's like a Map, but it works both ways, i.e. you can use the value as a key if you want.
Unless your ArrayList is sorted then O(n) efficiency is the best you can do. Unless by "quick way" you mean a method which does the iteration for you. Even in this scenario the answer is no since you're wanting to check data inside the String[] objects themselves.

How to sort map inside of List in java

List<Map<String,String>> consolidErr = new LinkedList<Map<String,String>>();
Map m1= new HashMap<String,String>();
m1.put("id","1");
m1.put("value","value1");
Map m2= new HashMap<String,String>();
m2.put("id","2");
m2.put("value","value2");
Map m3= new HashMap<String,String>();
m3.put("id","3");
m3.put("value","value3");
add all m1,m3 and m2 in list
then sort maps based on ids in map now i want maps in list as m1,m2 and m3.
Now I want to sort based on the ids in the map, I did that using iteration of list and keep first id of map as checker and compare with next it works if there any other better way than that using built-in methods.?Please give your ideas.am using bubble sort for this now.
The simplest way to do this in java (or at least, with the least mess) is to use a custom comparator.
The idea is that if you have objects with a natural sort (anything that extends Comparable) you can just ask for the sorting , e.g.
Collections.sort(List<Integer> ..
otherwise you can just pass in a Comparator that describes how you want objects compared, with any custom logic you want, e.g. (roughly - this is off the top of my head and doesn't have error checking, but should be enough to give you the idea) -
List<Map<String,String>> consolidErr = ...
enter code here
Collections.sort(consolidErr, new Comparator<Map<String,String>>(){
public int compare(Map<String,String> a, Map<String,String> b){
return a.get("id").compareTo(b.get("id"));}
})
In Java 8, we can sort the list of maps in a single line.
list.sort(Comparator.comparing((Map<String,String> mp) -> mp.get("Id")));
I would use instead the PriorityQueue
as a wrapper for your list. By providing the Comparator to the constructor when creating it, would assure you that your list will remain sorted after each insertion of a new element to the list.

How to print the hashmap values from the order they inserted into the hashmap

I have a HashMap which have strings as key and value,
HashMap dataSet = new HashMap();
dataSet.put("A1", "Aania");
dataSet.put("X1", "Abatha");
dataSet.put("C1", "Acathan");
dataSet.put("S1", "Adreenas");
I want to print it as the order it is inserted into the HashMap, So the output should be like,
A1, Aania
X1, Abatha
C1, Acathan
S1, Adreenas
Can anyone please tell me how to do this?
You can use a LinkedHashMap instead, which will preserve the insertion order. You can't do what you ask for with a standard HashMap.
This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
So the first line of your code would become:
Map dataSet = new LinkedHashMap();
You might also want to add generics as a good practice:
Map<String, String> dataSet = new LinkedHashMap<String, String>();
You can't a hashmap has no internal order
You will have to use another implementation of Map

HashMap Copy behavior I can't figure out

I am having trouble getting a separate copy of my HashMaps. By that I mean, once I have made a copy of the original, making a change to one does not change the other.
I have two HashMaps in this format:
HashMap<String, List<String> one = new HashMap<String, List<String>();
HashMap<String, List<String> two = new HashMap<String, List<String>();
I call the following function below (getTabSetDifferences) passing in one and two, as expected if there are some differences, those values will be removed from the HashMap
and it'll be different than before it was passed in for the test.
I want them to remain unchanged, so tried passsing in:
getTabSetDifferences((HashMap)one.clone(), (HashMap)two.clone())
This still changed the originals, so i created two more hashmaps in the same format, and cloned one and two to them, I used the new hashmaps to pass
in, and the original was still changed.
I then tried:
HashMap<String, List<String>> holdOne = new HashMap<String, List<String>>();
holdOne.putAll(one);
HashMap<String, List<String>> Holdtwo = new HashMap<String, List<String>>();
holdTwo.putAll(two);
Now I can do something like:
holdTwo.remove(key);
and the original is not changed, but if i call the method with holdOne and holdTwo it still changes the original one and two hashmaps, shouldn't they remain?
The method is working, and finding the differences i want, and is returned. But I still need the original two hashmaps to be as they were, but no matter which
way I call, what ever changes are made to holdOne and holdTwo changes the originals. Is that the expected behavior? If so, what is the proper way
to get a copy of a hashmap that is not tied to it.
getTabSetDifferences(holdOne, holdTwo);
public HashMap<String, List<String>> getTabSetDifferences(HashMap<String, List<String>> hmMain, HashMap<String, List<String>> hmSecond) {
HashMap<String, List<String>> hmDifferences = new HashMap<String, List<String>>();
for (Map.Entry<String, List<String>> entry : hmMain.entrySet()) {
if(hmSecond.containsKey(entry.getKey())) {
entry.getValue().removeAll(hmSecond.get(entry.getKey()));
if (entry.getValue().size() > 0)
hmDifferences.put(entry.getKey(), entry.getValue());
}
else {
hmDifferences.put(entry.getKey(), entry.getValue());
}
}
return hmDifferences;
}
The clone method doesn't do a deep copy.
You have 2 options.
create a deep copy method.
Use one of the Map implementations from the java.util.concurrent package like copyOnWrite
I suspect you are only copying the keys/values. This will not create copies of the lists.
Perhaps Guava's MultiMap is what you want?
If you copy the list as a list (i.e. copy it at list scope, rather than some lower level implementation), then the pointer behavior will be seen.... However if you copy from one list into a new list, then those string objects are independant.
Java's clone method should not be use in expectation that it will return distinct , deep copies of an object - immutability is not a central concept to the way clone works.
I agree with the above comment : either use a multimap in a library like guava, or google collections, or simply be very careful about your copying, and only copy at the primitive levels, (don't ever copy a collection and expect it to be independent) unless you've tested this explicitly .

Categories

Resources