Remove entries from Java LinkedHashMap - java

I have to compare two Excel files (with different data) and create two new Excel tables:
Table 1 contains all matching entries
Table 2 contains all entries that not match
Therefore I iterate over both Excel files and store the matching entries in a LinkedHashMap. In a second LinkedHashMap I store all entries from the Excel file. With this two Maps I want to identify the delta.
To identify the delta I compare both lists and now want to remove all entries from the complete list, if the entry is already in the list with the matching ones.
I tried different solutions - all with the result that the code is running but never an entry is really removed. Can anyone help please?
Heres my code:
// This code fills both Maps
LinkedHashMap<String, String> liste_matches = new LinkedHashMap<String, String> ();
LinkedHashMap<String, String> liste_complete = new LinkedHashMap<String, String> ();
while(worksheet1.getLastRowNum() >= j){
liste_complete.put(String.valueOf(worksheet1.getRow(j).getCell(18)), "");
// Counter for loop, loops trough Telekom datasets
int i = 1;
while(worksheet2.getLastRowNum() >= i)
{
if(String.valueOf(worksheet1.getRow(j).getCell(18)).equals(String.valueOf(worksheet2.getRow(i).getCell(9))))
{
if(!liste_matches.containsKey(String.valueOf(worksheet1.getRow(j).getCell(18)))){
liste_matches.put(String.valueOf(worksheet1.getRow(j).getCell(18)), "");
}
}
}
// build Excel table
}
This is my code I used to compare both lists and remove all entries from liste_complete that are already in liste_matches.
I first tried this (I inserted the ArrayList for my second try...). It's running but without any effect to the list.
ArrayList list = new ArrayList();
for(Map.Entry<String,String> keyDelta : liste_complete.entrySet())
{
for(Map.Entry<String,String> key : liste_matches.entrySet()){
if(keyDelta.equals(key)){
liste_complete.remove(keyDelta);
list.add(entry.getValue());
}
}
}
Afterwards I tried this but also without any effect to the List:
for(int c = 0; c < list.size(); c++)
{
String str = list.get(c);
liste_complete.remove(str);
}
I found this solution in StackOverflow, but that returns java.lang.IllegalStateException
Iterator<Map.Entry<String,String>> iter = liste_complete.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,String> entry = iter.next();
for(Map.Entry<String,String> key : liste_matches.entrySet()){
if(key.getValue().equalsIgnoreCase(entry.getValue())){
iter.remove();
}
}
}

AFAIK you can't remove element from a list you're iterating on.
I suggest you 2 solutions:
iterate on your lists to check for matching keys and store the match in the third list; then iterate on the third list and remove from liste_complete
refactor the first piece of code of your question so that you store in one list the matching values and in the other the non-matching. Pseudo code could be:
for worksheet1 row
for worksheet2 row
if(match)
liste_matches.add(...)
else
liste_non_matches.add(...)
In this way you do not have to remove elements afterwards.

Thanks a lot for your hints.
I already debugged the code but didn't understand the problem - I think it really was a problem of the complex input data.
I did not compare the keys via key.getKey() but only with key and that seems to cause problems in the comparison. Anyway, my code runs with this snippet:
for(Map.Entry<String,String> keyDelta : liste_Complete.entrySet()){
if(!liste.containsKey(keyDelta.getKey())){
delta_liste.put(String.valueOf(keyDelta), "");
}
}

Related

How can I iterate through a hashset within a hashmap?

I am trying to iterate through a hashmap which contains 8 entries. However one of these entries is a hashset 'balloon' with 2 objects within it. I want to add this to an array list so i can then iterate through it in a for loop/
First part of the code below works, I loop through the hashmap and look for the key I require which is 'balloon'. I need help to add the hashset to an array list.
I am getting a casting error when using Collectors.list and stream
//This is the hashmap I am looping through to find the balloon key
Map<String, Object> types = System.getPartyItems();
for (Map.Entry<String, Object> entry : types.entrySet()) {
if (StringUtils.contains(entry.getKey().toString(), "balloon")) {
//This is where I need to add the balloon hashset to a list to access the entries and values from within.
List<PartyItem> myPartyList = new ArrayList<>();
myPartyList.add (hash set of balloon objects)
Do i need to assign the hash set to a variable before i can set it to the list? Anything I've tried I am getting a casting error eg "class java.util.stream.ReferencePipeline$Head cannot be cast to class java.util.ArrayList"
Any help appreciated.
Thanks
Test if a value is a Set and if it is, add all items to your list.
if (StringUtils.contains(entry.getKey().toString(), "balloon")
&& entry.getValue() instanceof Set) {
myPartyList.addAll((Set)entry.getValue());
}
You can iterate like this:
for(String key: Map.keySet()){
if(StringUtils.contains(key, "balloon")){
Iterator<String> it = hashMap.get("balloon").iterator();
while(it.hasNext()){
// your code here
}
}
}
Instead of iterating through entry just iterate through keys and when you find the balloon get the hashset to iterate through it.
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
for(Object object: types.get(key)){
//do what you need with object
}
}
}
After your edit it should be like this
for(String key: types.keySet()){
if(StringUtils.contains(key, "balloon")){
ArrayList<Set<PartyItem>> myList = new ArrayList();
myList.add(types.get(key));
}
}
Usually you structure your hashmap as <key, value> and you access your values via their corresponding keys. But they have to match exactly.
In your case your hashmap would look like this:
Map<String, Object> partyItems = myPartyList.getPartyItems();
// or maybe even
Map<String, PartyItem> partyItems = myPartyList.getPartyItems();
And getting the value is as easy as:
Object partyItem = partyItems.get("baloon");
If you are not sure if your paryItems contain a value for your key baloon you can check that first:
if (partyItems.contains("baloon")) {
Object partyItem = partyItems.get("baloon");
}
If you are looking for a part of the key matching baloon:
List<PartyItem> myFilteredPartyItems = partyItems.entrySet().stream()
.filter(e -> e.getKey().contains("baloon"))
.collect(Collectors.toList()))
This is called stream oriented programming (take a look at the Java Stream API), and if your run at least Java 8 you can use those.
And what it does, is turn the entries of the List to a stream, then remove everything which does not contain baloon in the key, and turn the resulting stream, which was not removed back to a list.
Here you also find a very informative tutorial on how to use streams in Java.

Merging n number of list into a Map based on a value in List

I have the following objects in an ArrayList and a value in this object is illustrated as the numbers at the beginning, which are Id of something.
I need to create a Map object, whose key should be the id of objects and whose values should be the objects with id. At the end of the day, I would like to have a Map something like that.
I have already solved this problem with two for loops and lots of if statements but it seems very ugly to me.
Any cleaner solution would be appreciated.
Map<Integer, List<Foo>> result = list.stream().collect(Collectors.groupingBy(Foo::getId));
Edited to fit the question edit, it is as simple as this:
ArrayList<Element> list = ...;
HashMap<Integer, List<Element>> map = new HashMap<Integer, List<Element>>();
for(Element e : list) {
ArrayList<Element> auxList;
if(map.contains(e.getId()) {
auxList = map.get(e.getId());
} else {
auxList = new ArrayList<Element>();
map.put(e.getId(), auxList);
}
auxList.add(e);
}
Just iterate over the starting list and add the elements to the map. If the map already contains the id, add it to the list. If not, create a new list.

Removing from a hashmap a specific value and the key

I want to remove a specific value from the hashmap and the key from that value. Look, for example if I have
hashMap.put(cold, frozen)
hashMap.put(cold,hard)
, in my graphic interface i will have cold=[frozen,hard].If I want to erase hard I want cold = [frozen] to stay
My hashMap is private HashMap<String,ArrayList<String>> hashMap ;
Here is what I tried but it's not good enough because if I have at 2 different key the value i want to remove, it only removes the value for the first and if I have for ex cold=[frozen,hard] and I erase hard it doesn't keep cold=[frozen];
for(String key : hashMap.keySet()){
int siz = hashMap.get(key).size();
for(int i = 0; i< siz;i++){
if(hashMap.get(key).get(i).equals(cuvant)){
s.remove(hashMap.get(key).get(i));
siz--;
hashMap.remove(key);
}
}
}
I forgot to mention that s is the arrayList with the values.
Are you putting an ArrayList with the values in a hashmap?
If so, then check for list size first:
if (! hashMap.get(key).isEmpty()){
hashMap.get(key).remove(ValueToRemoved)
}
add a condition
if (hashMap.get(key).isEmpty())
before
hashMap.remove(key);
This will ensure you delete a key only if the list associated with it is completely empty.
Also, make sure you do NOT keep iterating (the inner loop) after removing an element from the list if you use a for-each loop, it will get you a ConcurrentModificationException. If your list can have the same value multiple times (and should be removed multiple times), use the Iterator API rather than for-each loop.
Try this :-
HashMap<String, ArrayList<String>> m = new HashMap<>();
Iterator<Map.Entry<String,ArrayList<String>>> iter = m.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,ArrayList<String>> entry = iter.next();
ArrayList<String> list = entry.getValue();
for(int i = 0 ; i < list.size() ; i++){
if(list.get(i).equals(cuvant)){
list.remove(i);
}
}
if(list.isEmpty())
iter.remove();
}

Count the occurences of a particular variable inside an ArrayList

In my class Feeds I have along with other members a member variable called "Date" which is of String type. I have an ArrayList of Feeds objects. I want to find the occurrences of objects which have the same date String. The occurrences can then be put in a HashMap that contains the String Date as key and # of occurrences as value.
Something along these lines:
List<Feeds> m_feeds = new ArrayList<Feeds>();
//add all feeds objects
m_feeds.add(...);
int occurrences = 0;
HashMap<String, Integer> repeatedDatabase = new HashMap<String, Integer>();
for (Feeds f : m_feeds){
occurrences = Collections.frequency(m_feeds, f.date);
// i know this method compares objects but i want to know how
// only a single variable can be done
repeatedDatabase.put(f.date, occurrences);
}
Other than giving you a simple solution, I took the liberty of fixing some things in your code please take a look:
List<Feeds> mFeeds = new ArrayList<>(); //If you are using Java 7+ you do not need to declare explicitly the Type in Diamonds. If you aren't, ignore this. Also fixed name to adapt to Java standards.
//add all feeds objects
m_feeds.add(...);
HashMap<String, Integer> repeatedDatabase = new HashMap<>(); //See Above.
for (Feeds f : m_feeds){
String s = f.date; //Suggestion: use a getter method, do not make public variables accessible outside class
Integer i = repeatedDatabase.get(s);
if (i == null){
repeatedDatabase.put(s, 1);
} else {
repeatedDatabase.put(s, i+1);
}
}
Your code will work if you properly overrode equals and in the Feeds class to return true for two Feeds instances having the same date (since if you try to put the same key in the Map twice, the new value will override the old value, and since in your case the values would also be the same, it would make no difference). However, each call to Collections.frequency would iterate over the entire List, which would give you an O(n^2) time complexity.
One way to make it more efficient :
for (Feeds f : m_feeds){
if (!repeatedDatabase.containsKey(f.date)) {
occurrences = Collections.frequency(m_feeds, f.date);
repeatedDatabase.put(f.date, occurrences);
}
}
This would still do more iterations than necessary. It would call Collections.frequency once for each unique date, which means you would iterate the List as many times as there are unique dates.
A more efficient implementation will not use Collection.frequency at all. Instead, you'll iterate just one time over the list and count the number of occurrences of each date yourself. This would give you an O(n) time complexity.
for (Feeds f : m_feeds){
if (!repeatedDatabase.containsKey(f.date)) {
repeatedDatabase.put(f.date, 1);
} else {
repeatedDatabase.put(f.date, repeatedDatabase.get(f.date)+1);
}
}
Why don't use directly the hashMap?
you can do something like
HashMap<String,Iteger> map = new HashMap<>();
for (Feeds f : m_feeds){
if (map.contains(f.getDate()) { // use the method to get the date
map.put(f.getDate(),map.get(f)+1);
else
map.put(f.getDate(),1);
}
I didn't test the code but it should work.
A small update to Angelo's answer..pushing it a bit further.. you can also use a map of string,int[] like this
Map<String,int[]> map = new HashMap<>();
int[] countArray = map.get(key);
if(countArray == null)
map.put(key, new int[]{0});
else
countArray[0]++;
Using the beauty of references :)

How to use collection in Java

I want to use Java collection to find the words in the list that begin with the startup letter:
example:
TreeMap<String, Double> tm = new TreeMap<String, Double>();
// Put elements to the map
tm.put("Zara", new Double(3434.34));
tm.put("Mahnaz", new Double(123.22));
tm.put("Ayan", new Double(1378.00));
tm.put("Daisy", new Double(99.22));
tm.put("Qadir", new Double(-19.08));
Toast.makeText(getApplicationContext(), ""+tm.get("Zar"),Toast.LENGTH_SHORT).show();
in this case it will show null. But what i want to do is to show all the words that start with that letter. How can i do this? Thanks in advance
Since TreeMap is a NavigableMap, it is computationally cheap to iterate the map starting from a given key:
String prefix = "Zar";
for (String person::tm.tailMap(prefix).keySet()) {
if (person.startsWith(prefix)) {...}
}
There are a few choices:
If you always go from the first three characters then do a multimap - Map<String, List<Data>> Where Data contains String name and double double and the key is the first three letters of all the names.
You can scan through the TreeMap and because it is sorted at least you know you can stop once you get past Zar - but this will still be inefficient.
You can use a database (embed a Derby Database for example) and use the indexing/search/query functionality of the database.
You can build your own tree structure branching on each character in the word. Then root->z->a->r would then give you every word beginning with zar. root->b->o would give you every word beginning with bo, etc.
TreeMap<String, Double> tm = new TreeMap<String, Double>();
//...add values.
//get all keys
Set<String> keys = tm.keySet();
Set<String> result = new HashSet<String>();
for(String key : keys){
//check the beginning of the keys
if(key.startsWith("Zar"){
result.put(key);
}
}
//get the values for your collected keys
for(String key : result){
double value = tm.get(key);
}
Just reading when to use what collection will only help you if you run across the exact same situation in your code. If you don't understand the roots of why a given data structure is good for a problem, you won't be able to apply this to your own code.
this link may help you
You only have to Iterate over the list and check if the key starts with the given String.
Example:
for (String elem : tm.keySet()) {
if(elem.startsWith("Zar")) {
System.out.println(elem);
}
}
output:
Zara
and if you want to ignore the case:
if(elem.toLowerCase().startsWith("zar".toLowerCase()))
So How can you achieve this?
First find all the keys of HashMap by
tm.keySet()
then use iterator on keys and match with the string.See example below
String abc = "Zar";
HashMap s = new HashMap();
s.put("Zara", new Double(1.0));
Set x =s.keySet();
Iterator iter = x.iterator();
while (iter.hasNext()) {
String key = iter.next().toString();
if(key.startsWith(abc)){
System.out.println(s.get(key));
}
}

Categories