Overwriting when using Map.putAll() - java

I am having some difficulty when using Map.putAll(). Instead of updating / adding particular records to my main map, it is overwriting the entries:
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> cache = new ConcurrentHashMap<String, ConcurrentHashMap<CardType, Card>>();
The three separate maps are generated as below:
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> businessCardCache = buildBusinesscardCacheValues(connection, getBusinessCards);
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> personalCardCache = buildPersonalcardCacheValues(connection, getPersonalCards);
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> socialCardCache = buildSocialcardCacheValues(connection, getSocialCard);
cache.putAll(businessCardCache);
cache.putAll(personalCardCache);
cache.putAll(socialCardCache);
What should happen is user ben for example should be the key and he should have a business a personal and a social card. What in fact happens is he only ends up with a socialCard as I assume it is the last to run and therefore overwrites the previous.
How should I approach modifying this?
Thanks

Your current initialization of cache would cause cache.putAll(personalCardCache); to replace the values added by cache.putAll(businessCardCache); for keys that appear in both maps.
If you want cache to contain all the cards of each user (taken from all 3 input maps), you should initialize it in a different way :
for (String key : businessCardCache.keySet()) {
ConcurrentHashMap<CardType, Card> cards = null;
if (cache.containsKey(key) {
cards = cache.get(key);
} else {
cards = new ConcurrentHashMap<CardType, Card>();
}
cards.putAll (businessCardCache.get(key));
}
Then you do the same for the other 2 maps.

Related

How to create multiple key value hashmaps from a resultset

I would like to create multiple hashmaps from a resultset.
The final result should be something like below;
{
slot_name = recommend,
data = 7,
},
{
slot_name = service,
data = Good,
},
{
slot_name = staff,
data = Great,
},
I tried as below:
HashMap<String, String> data = new HashMap<String, String>();
while (resultSet.next()) {
data.put("slot_name", resultSet.getString("name"));
data.put("data", resultSet.getString("param_value"));
}
But when I printout the value of the hashmap, I get one record as below
System.out.println(data);
{
slot_name = staff,
data = Great,
}
How can I achieve this? Someone assist, thank you
I would recommend to have a list and create a model class(instead of HashMaps) for "slot_name" and "data". Inside loop, construct object and add to the list. The reason, you are not getting as expected, is because, HashMap will have unique keys. So, for the same key when the value is again added, it will get updated.
class YourModel {
String slotName;
String data;
}
// inside loop
list.add(new YourModel(resultSet.getString("name"), resultSet.getString("param_value"));
A HashMap is a key value store. If you put the same key more than once, previous will be overwritten. This is the reason you saw only the last entry in the output.
if you want multiple maps, well create multiple ones.
Eg.,
List<HashMap<String,String> maps = new ArrayList();
while (resultSet.next()) {
HashMap<String, String> data = new HashMap<String, String>();
data.put("slot_name", resultSet.getString("name"));
data.put("data", resultSet.getString("param_value"));
maps.add(data);
}

Hashmap return value by other hashmap keys

I have two hashmaps one is containing keys and other is containing key with object value.
Here are my two maps and its value
1st one is:
newProdList = [18=, 2=, 21=1099887, 5=, 22=1099888, 7=, 14=]
and 2nd one is:
oldList = [2=Stock [location=AAQ-08-2, stockQty=150,
productCode=null, productName=Emergence Men's Running Shoes,
division=Shoes, category=Running], 3=Stock [location=AAR-01-1,
stockQty=192, productCode=19234402, productName=Men's Running Shoes
19234402, division=Shoes, category=Running], 4=Stock
[location=BAN-08-1, stockQty=190, productCode=19108206,
productName=Carson 2 New Core Men?s Running Shoes, division=Shoes,
category=Running] , 21 =Stock [location=BAN-08-1, stockQty=190,
productCode=19108206, productName=Carson 2 New Core Men?s Running
Shoes, division=Shoes, category=Running]]
I want to iterate newProductList and use there keys in oldList that generate List of objects.
It is simply done by this:
List<Stock> stocks = new ArrayList<>();
for(Entry<?, ?> e: newProductList.entrySet()){
Stock s = (Stock) oldProdList.get(e.getKey());
stocks.add(s);
}
System.out.println(stocks);
But I want to use Stream api.
Since you're only using the keys of newProductList I'd suggest iterating over keySet() instead.
You then could do something like this:
List<Stock> stocks = newProductList.keySet().stream() //stream over the keys
.map(oldProdList::get) //map by calling get() on the old list
.filter(Objects::nonNull) //remove nulls
.collect(Collectors.toList()); //build the result list
Here we iterate over the keys, map them by doing a lookup, filter on non-null results (in case the lookup fails) and collect the result.
Iterate over the entrySet to get the corresponding key from newProdList in oldList and set the value from this entry from oldList in newProdList.
More reading here about Map Entry
Map<String,String> newProdList = new HashMap<>();
newProdList.put("18", null);
newProdList.put("2", null);
newProdList.put("21", "1099887");
newProdList.put("5", null);
newProdList.put("22", "1099888");
newProdList.put("7", null);
newProdList.put("14", null);
Map<String,String> oldList = new HashMap<>();
oldList.put("2", "Stock [location=AAQ-08-2, stockQty=150, productCode=null, productName=Emergence Men's Running Shoes, division=Shoes, category=Running]");
oldList.put("3", "Stock [location=AAR-01-1, stockQty=192, productCode=19234402, productName=Men's Running Shoes 19234402, division=Shoes, category=Running]");
oldList.put("4", "Stock [location=BAN-08-1, stockQty=190, productCode=19108206, productName=Carson 2 New Core Men?s Running Shoes, division=Shoes, category=Running]");
oldList.put("21", "Stock [location=BAN-08-1, stockQty=190, productCode=19108206, productName=Carson 2 New Core Men?s Running Shoes, division=Shoes, category=Running]");
newProdList.entrySet().stream().forEach(e -> e.setValue(oldList.get(e.getKey())));
More explanation with this nice schema, as requested.

Pass return value to two different methods

I have a class with two methods: the startAPI() calls the API classes to extract entities and returns the entities and the occurrence of the entities. I need this return value in two different methods from another class, but as soon as I call the second method (countApiOcc()) the map I pass is empty. How can I use the returned map in two different methods?
public class Topic {
public void calculateNoFeedback(String language, List<String> api, List<String> corr) {
Map<String, Object> apis = startAPI(api, textList);
CountTopics countT = new CountTopics();
ArrayList<String> topics = countT.getTopics(apis);
countT.countApiOcc(topics, apis);
}
public Map<String, Object> startAPI(List<String> selectedAPI, List<String> text) {
Map<String, Object> apisValues = new HashMap<String, Object>();
//do stuff to extract the entities and return entities
return apisValues;
}
}
The CountTopic() class looks as follows, and, explained in short, user can select which or how many APIs he wants to use to extract entities and in the class CountTopic() the method getTopics() should find the topics every selected API found and countApiOcc() I need the frequency of the selected entities (all of this works) it is just the map I need in the second method.
public ArrayList<String> getTopics(Map<String, Object> apiV) {
System.out.println("apiV: "+apiV);
Iterator iterator = apiV.entrySet().iterator();
mapSize = apiV.size();
System.out.println("Size of the map: "+ mapSize);
while (iterator.hasNext()) {
Map.Entry entries = (Map.Entry)iterator.next();
String key = entries.getKey().toString();
switch(key) {
case "valuesMS":
Map<String, Object> mapMicrosoft = (Map<String, Object>) apiV.get(key);
ArrayList<String> microsoft = (ArrayList<String>) mapMicrosoft.get("topicArrayMS");
microsoftTopicLowerCase.addAll(microsoft);
topicsMultiset.addAll(microsoft);
break;
case "valuesGate":
Map<String, Object> mapGate = (Map<String, Object>) apiV.get(key);
ArrayList<String> gate = (ArrayList<String>) mapGate.get("topicArrayGA");
//store the values for finding the topics which are found from every selected API
//store the values from the api to lower case to find the index later (needed for how often this api found the topic
gateTopicLowerCase.addAll(gate);
topicsMultiset.addAll(gate);
break;
}
iterator.remove();
}
//rest code: compare the Arrays to find the same topics
iterator.remove();
There's your culprit. You're emptying your map. Don't do this, and it will work. From my limited view on your code, there doesn't seem to be any reason to modify your map. But in case it would be necessary, you should make a copy of the map at the beginning of your method, and work on this copy. Generally it's a bad idea to modify your input parameters, unless that is the specific purpose of that method.

Size of HashMap not increasing

I go through a loop three times and call this method each time:
// class variable
private HashMap<String, ffMotorskillsSession> tempMap;
tempMap = new HashMap<String, ffMotorskillsSession>();
for loop {
addMotorskillsSession(session);
}
private void addMotorskillsSession(ffMotorskillsSession pSession) {
StringBuilder sb = new StringBuilder();
sb.append(pSession.period).append(":").append(pSession.section)
.append(":").append(pSession.class_name).append(":")
.append(pSession.semester).append(":").append(pSession.grade);
tempMap.put(sb.toString(), pSession);
Log.d("Size: ", String.valueOf(tempMap.size()));
}
Everytime I Log the size each time it passes thru it stays at one.
Can anyone see why?
A Map stores key/value pairs, with only one value per key. So if you're calling put with the same key multiple times, then it will correctly stick to the same size, only having a single entry for that key.

How to check if a string is in an arrayList inside a hashmap

So I have a hashmap
HashMap<String, ArrayList<String> gMap = new HashMap<String, ArrayList<String>();
And when someone creates a group, the group leader is added to the key of the hashmap and then all the users inside the group are added to the arraylist
gMap.get(groupLeader).add(user);
I'm trying to make it so that only group leaders are allowed to invite players, but if a player is not part of any group and invites another user then a group is automatically created and the player becomes the group leader.
So, normally I would just do this
for(ArrayList<String> list : gMap.values()){
if(list.contains(user)){
//do something since the player is not part of the list
}
}
But I cannot do that since there could be multiple arrayLists, so even though the user is not part of one arrayList it does not mean that they aren't inside another.
So I'm curios how I would check all the arrayLists and do something only if the user is not part of any of them.
You're actually creating a Multimap (a mapping of keys to collections of values) data structure here, and you'll find if you use one directly you won't have to reinvent the wheel as you are now. Guava defines a very nice Multimap interface, including an ArrayListMultimap that stores the data you want, and has a containsValue() method that cleanly does what you need. As mentioned by others, contains checks against a list are slow, you could use HashMultimap to do these contains checks more efficiently if you don't actually care about order, or LinkedHashMultimap if you really do.
And if you aren't already using Guava, you're missing out - it provides countless excellent utilities and good practices.
Use a boolean value that you only change the value of if a list contains the user - and break out of the loop if it does.
boolean notInAnyList = true;
for(ArrayList<String> list : gMap.values()){
if(list.contains(user)){
notInAnyList = false;
break; // No point in iterating any further
}
}
if (notInAnyList) {
// Handle user not being in any of the lists here
}
So here is a code sample
boolean userIsPartOfGroup = false
for(ArrayList<String> list : gMap.values()){
if(list.contains(user)){
userIsPartOfGroup = true;
break;
}
}
if(!userIsPartOfGroup){
gMap.add(user).add(new ArrayList(user));
}
First, I would use a set instead of a list (Java 7 syntax):
Map<String, Set<String> gMap = new HashMap<>();
When I understand your goal right, this may be a solution:
if (isLeader(groupLeader, gMap)) {
gMap.get(groupLeader).add(user);
} else if (isMember(groupLeader, gMap)) {
throw new UnsupportedOperationException("Member " + groupLeader + " is not a leader and must not invite " + user);
} else {
addNewGroup(groupLeader, gMap).add(user);
}
Here are the helper methods:
private boolean isLeader(String player, Map<String, Set<String> gMap) {
return gMap.keys().contains(player);
}
private boolean isMember(String player, Map<String, Set<String> gMap) {
for (Set<String> members : gMap.values()) {
if (members.contains(player)) {
return true;
}
}
return false;
}
private Set<String> addNewGroup(String leader, Map<String, Set<String> gMap) {
Set<String> players = new HashSet<>();
gmap.put(leader, players);
return players;
}

Categories

Resources