Removing duplicate linked value from ArrayList java - java

we are facing a challenge in implementing one of our client requirement, using java as code technology.
we need to format the input given by the system, to display the data in a userfriendly format.
below is the data as input to our program.
its a java map with key as string and value as a list of strings
OP1004=[],
OP1006=[OP1004]
OP1005=[OP1003]
OP1009=[OP1006, OP1044, OP1046, OP1004],
OP1016=[OP1008, OP1009, OP1044, OP1005, OP1004],
output we are expecting as below.
OP1004=[],
OP1006=[OP1004]
OP1005=[OP1003]
OP1009=[OP1006, OP1044, OP1046], //here 1004 is deleted
OP1016=[OP1008, OP1009, OP1005, OP1004], //here 1044 is deleted
here, if we observe closely, we want to delete the repeated values from the list, that is
if we go thru the bottom, that is OP1016 contains the list as OP1008, OP1009 etc.. where OP1009 also has the list as OP1006, OP1044 etc.. where OP1006 again has the list as OP1004
so here we want to delete OP1004 from OP1009 because its already mapped to other(OP1006) OPID which is part of OP1009.
actually we are displaying this in a hierachy/flowchart diagram, so we want to delete duplicate navigation to the items.
Please help us in providing solution. appreciate your help in advance.
Thanks

Your problem boils down to checking whether elements of a list are present in other lists but these list are present in a map so you need to maintain the key-value pair.
This is how you can achieve that.
Loop over map and get the key and list of values, add a condition to check whether list is empty and contains more than 1 values.
Loop over same map again, get the key and add a condition to check whether the first loop key is equal to second loop key this is to avoid checking for same list. Add one more condition to check whether list is empty and contains more than 1 values.
Now you can remove elements from a list if those elements are present in another list by using List.removeAll() method.
Sample code
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Example {
public static void main(String[] args) {
List<String> firstList = new ArrayList<String>();
firstList.add("");
List<String> secondList = new ArrayList<String>();
secondList.add("OP1004");
List<String> thirdList = new ArrayList<String>();
thirdList.add("OP1003");
List<String> fourthList = new ArrayList<String>();
fourthList.add("OP1006");
fourthList.add("OP1044");
fourthList.add("OP1046");
List<String> fifthList = new ArrayList<String>();
fifthList.add("OP1008");
fifthList.add("OP1009");
fifthList.add("OP1044");
fifthList.add("OP1005");
fifthList.add("OP1004");
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("OP1004", firstList);
map.put("OP1006", secondList);
map.put("OP1005", thirdList);
map.put("OP1009", fourthList);
map.put("OP1016", fifthList);
for (Map.Entry<String, List<String>> keyAndValue: map.entrySet()) {
String key = keyAndValue.getKey();
List<String> values = keyAndValue.getValue();
if (values.isEmpty() || (values.size() < 2)){
continue;
}
for (Map.Entry<String, List<String>> mapKeyAndValue: map.entrySet()) {
String key1 = mapKeyAndValue.getKey();
if (key.equals(key1)){
continue;
}
List<String> values2 = mapKeyAndValue.getValue();
if (values2.isEmpty() || (values2.size() < 2)){
continue;
}
values2.removeAll(values);
}
}
for (Map.Entry<String, List<String>> keyAndValue: map.entrySet()) {
System.out.println("Key is " + keyAndValue.getKey() + " Values are " + keyAndValue.getValue());
}
}
}
Check Output Here
Key is OP1004 Values are []
Key is OP1006 Values are [OP1004]
Key is OP1005 Values are [OP1003]
Key is OP1009 Values are [OP1006, OP1044, OP1046]
Key is OP1016 Values are [OP1008, OP1009, OP1005, OP1004]
Note - I assumed that you are using HashMap as you didn't specify what kind of map you are using and if you want the map to be ordered then use LinkedHashMap
as HashMap does not store elements in order.

A simple solution would be to change the
Map<String, List<String>> to Map <String<Set<String>>
Let me explain it in a better way:
List list = map.get(str);
Set<String> set = new HashSet<>();
set.addAll(list);
list.clear();
list.addAll(set);
now you can use it in the way you want..
Let me know if you didnt understand any part of it

Pseudo-code: if key exists then remove it from any values (of other keys)
for (String key : map.keySet()){ // iterate through all keys
for (Map.Entry<String, List> mapEntry : map.entrySet()){ // again iterate but this time get Map.Entry
if (!mapEntry.getKey().equals(key)){ // if entry is for other key
((List)mapEntry.getValue()).remove(key); // then remove key from list
// if this map cannot be modified you can keep key, mapEntry in another map here...
}
}
}

Create a set to hold all the values previously displayed. If an item can not be added to this set, then do not add it at all.
Map<String, String[]> original = ...
Set<String> used = new HashSet<>();
Map<String, String[]> reduced = original
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
entry -> Arrays.stream(entry.getValue())
.filter(used::add)
.toArray(String[]::new)));

Related

Displaying key-values in HashMap

I have 2 questions regarding the code bellow,
1.I have the key "two" twice in my hashmap, while printing, "two" is displayed only once.Why its not displaying "two" twice?
2.How to selectively display the key "two"?
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
public class main {
public static void main(String[] args){
HashMap<String,String> myMap = new HashMap<String,String>();
myMap.put("one", "1");
myMap.put("two", "2");
myMap.put("three", "3");
myMap.put("two", "4");
Set <String> mySet =myMap.keySet();
Iterator itr = mySet.iterator();
while(itr.hasNext()){
String key = (String) itr.next();
System.out.println(key);
}
}
}
Hashmaps may only have one key entry per key in their keyset. The second time you put a key-value pair in the map will override the first when you are using the same key for Maps (which include HashMap).
If you want a one-to-many mapping, you can use a Multimap or a HashMap that maps an object to a collection of objects (although Multimap will most likely make this easier for you)
To display a value for a given key, use:
System.out.println(myMap.get(myKey));
System.out.println(myMap.get("two"));
Hashtable and HashMap are one-to-one key value store. That means that for one key you can have only one element. You can still achieve what you want with:
HashMap<String, List<String>>
when you add an element to the map, you have to add it to the list for this key, i.e.
public void add(String key, String value) {
List<String> list = map.get(key);
if (list == null) { //if the list does not exist, create it, only once
list = new ArrayList<String>();
map.put(key, list);
}
list.add(value);
}
And now, when you want to get all elements with this key:
List<String> elements = map.get("two");
The list will contain all elements you added.

How to get key from map using list as a value

I am making something like tags using Java collections. I made a map using list as a value.
Can I get a key searching by words from list? How I can do that?
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<String>();
list1.add("mammal");
list1.add("cute");
list2.add("mammal");
list2.add("big");
map.put("cat", list1);
map.put("dog", list2);
If I understand you correctly, you want to obtain the key given one of the value in the list stored as the corresponding value? Of course, you can always get all these lists using the values() method of the Map interface and then iterate over those. However, how about having a second map where you use your tags as keys and store a list of all the entries carrying this tag? For large data sets, this will probably perform better.
for (Entry<String, List<String>> entry : map.entrySet()) {
if (entry.getValue().contains(animalYouSearch)) {
System.out.println(animalYouSearch + " is in " + entry.getKey());
}
}
Output if you search for "mammal":
mammal is in cat
mammal is in dog
There is no 'magic' way for it, you need to search inside the values and then report the correct key.
For example:
String str = "cute";
List<String> matchingKeys = map.entrySet().stream().filter( e -> e.getValue().contains(str))
.map(e -> e.getKey()).collect(Collectors.toList());
But you probably want to store your data other way arround, the list of "features" being the key, and the value the animal name.
If you want to retrieve set of tags, use this method:
public Set<String> findMatchingKeys(Map<String, List<String>> map, String word){
Set<String> tags = new HashSet<String>();
for(Map.Entry<String,List<String> > mapEntry : map.entrySet()){
if(mapEntry.getValue().contains(word))
tags.add(mapEntry.getKey());
}
return tags;
}

Compare keys with llist of values Java

Assuming the TreeMap<String,List> one and its copy as bellow,
i want to compare all keys in the first one with all values in the second one. If a key has no match in values, as AUF_1060589919844_59496 and AUF_1421272434570_1781 in this case, i want to get the key and its values back.
{AUF_1060589919844_59496=[AUF_1086686287581_9999,
AUF_1086686329972_10049, AUF_1079023138936_6682],
AUF_1087981634453_7022=[AUF_1421268533080_1741, AUF_1421268568003_1743],
AUF_1421268533080_1741=[AUF_1421268719761_1776],
AUF_1421272434570_1781=[AUF_1087981634453_7022]}
copy of above
{AUF_1060589919844_59496=[AUF_1086686287581_9999,
AUF_1086686329972_10049, AUF_1079023138936_6682],
AUF_1087981634453_7022=[AUF_1421268533080_1741, AUF_1421268568003_1743],
AUF_1421268533080_1741=[AUF_1421268719761_1776],
AUF_1421272434570_1781=[AUF_1087981634453_7022]}
What I understand from your problem is to get key which are not there in values and its value also. I think there is no need to create copy of it. I am posting a code snippet, I think this will certainly help you
Map<String, List<String>> map = new HashMap<String, List<String>>(); //Add elements in map
Collection<List<String>> list = map.values();
List<String> values = new ArrayList<String>();
for (List<String> listValues : list) {
values.addAll(listValues);
}
for (String key : map.keySet()) {
if (!values.contains(key)) {
System.out.println("key ---->" + key);
System.out.println("Values ------->");
for (String value : map.get(key)) {
System.out.println(value);
}
}
}
If my assumption is correct you want all the keys that are not values;
well this is very dirty way of doing it.
Set<String> keys= new HashSet<String>(one.keySet()); //ensure we don't mess up with the actual keys in the Map
for(List list : one.values()){
keys.removeAll(list); //remove all those Keys that are in values
}
// print out keys that are not values
System.out.println(keys);
Using set will make life easy, as it doesn't contain duplicates, and we can remove values very quicky (using removeAll() method)

Merging a Set and List to HashMap

I have one set whose keys are String and List of type String I want to make a HashMap out of this Set and List. The set contains categories and the list contains places belonging to those categories. Following is what I tried
Set<Entry<String, Integer>> setUserPreferences = sortedUserPreferences.entrySet();
Map<String , Integer> sortedPlaces = new HashMap<String, Integer>();
List<String> topPlaces = new ArrayList<String>();
Map<String , List<String>> finalPlaces = new HashMap<String, List<String>>();
for (Entry<String, Integer> entry : setUserPreferences) {
sortedPlaces = placesService.sortPlaces(categorisedPlaces.get(entry.getKey()));
int counter = 0;
for (Map.Entry<String, Integer> sortedplace : sortedPlaces.entrySet()) {
topPlaces.add(sortedplace.getKey());
counter++;
if(counter == 5){
sortedPlaces.clear();
break;
}
}
finalPlaces.put(entry.getKey(), topPlaces);
topPlaces.clear();
}
First I iterate over the set and for each key I get the sorted Places, out of the sorted places I pick the top 5 places for each category, Finally I put it in the map where the key is the category and value is the list of top 5 places in that category.
I need to clear the topPlaces list for each iteration over the set because I dont want to have the places from one category appear in the other, but once I put the list in map(finalPlaces) and clear the list it also clear the map values.
How can I clear the list without clearing the map values.
Thanks
topPlaces is a reference to an Object, not a primitive. So, if you store it in the map, you have two references to the same Object, one inside the Map and one outside. If you wipe one, you wipe both.
If you want to clear topPlaces without deleting the stored list, you need to copy it before adding it to the Map.
Something like this:
finalPlaces.put(entry.getKey(), new ArrayList<String(topPlaces));

How to put multiple values in Map from a list

I have a list gotitems.
ArrayList<String> gotitems = new ArrayList<String>();
i need to put that list in a hashmap called map.
Map<String,String> map = new HashMap<String,String>();
i had tried this :
for(String s:gotitems){
map.put("a",s);
}
gotitems contains :
First
Second
Third
But the output of :
System.out.println(map.values());
gives :
Third
Third
Third
i had even tried this :
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
but this is also not working.
What am i doing wrong here ?
As per Map put(K,V) method docs
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value.
You are ovverriding the key each time here .
for(String s:gotitems){
map.put("a",s);
}
change the key each time and try like
for(String s:gotitems){
map.put(s,s);
}
This is because you are putting all the items in the map against the same key "a"
map.put("a");
You need to store each element against a unique key so add something like this:
int count = 0;
for(String s:gotitems){
map.put("a" + count,s);
count++;
}
You are trying to put three Strings in the map under the same key "a". Try to use unique keys for your values.
You're putting all your items in the Map with the same key: "a".
You should have a unique String key for each value.
For instance:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
Map<String, String> map = new LinkedHashMap<String, String>();
for (String s: list) {
map.put(s, s);
}
System.out.println(map);
Output:
{one=one, two=two, three=three}
Note the LinkedHashMap here: it maintains the order in which you put your key/value pairs.
Edit Of course if your List does not have unique values, moving its values as keys to a Map will overwrite some of the Map's values. In that case you want to ensure your List has unique keys first, or maybe use a Map<Integer, String> with the index of the List's value as key to the Map, and the actual List value as value to the Map.
When you write
for(String s:gotitems){
map.put("a",s);
}
you will trash any existing entry in the map held against the key "a". So after your iteration, your map will contain just one entry corresponding to the last iterated value in gotitems.
To use a map effectively you need to consider what your keys will be. Then use map.put(myKeyForThisItem, s) instead. If you don't have an effective scheme for the keys then using a map is pointless as one tends to use the keys to extract the corresponding values.
As for your second approach, it would be helpful if you could define "it is not working" a little clearer: perhaps iterate through the map and print the keys and values.
Please note that in a map, a key can point to at most one value. In your case, you are doing the following mappings:
"a" -> "one"
then you overwrite it as
"a" -> "two"
then you overwrite it as
"a" -> "three"
remember: a key can point to at most one value. However, a value can be pointed at by multiple keys.
This is wrong:
for(String s:gotitems){
map.put("a",s);
}
Since you are using "a" common key for all values, last inserted key-value pair would be preserved, all previous ones would be overridden.
This is also not correct:
for(String s:gotitems){
for(int j=0;j<gotitems.size();j++){
map.put("a"+j,s);
}
}
you are putting n*n times into map, though you want only n (gotitems.size()) items into map.
First decide on key which you want to use in map, copying List into Map one approach could be use index as key:
for(int j=0;j<gotitems.size();j++){
map.put("KEY-"+j,gotitems.get(j));
}
Output should be:
KEY-0 First
KEY-1 Second
KEY-2 Third
I have reproduce your codes. The problem is that you are assigning the same key to different value. This should work.
import java.util.*;
public class testCollection{
public static void main(String[] args){
ArrayList<String> gotitems = new ArrayList<String>();
gotitems.add("First");
gotitems.add("Second");
gotitems.add("Third");
Map<String,String> map = new HashMap<String,String>();
String x = "a";
int i = 1;
for(String s:gotitems){
map.put(x+i,s);
i++;
}
System.out.println(map);
}
}

Categories

Resources