I am building a program that decides which group of people will survive and trace all the attributes. Therefore, I use one ArrayList to save the survived attributes, and another save the total attributes for the coming survival ratio calculation.
I've confirmed that my attributes are saved correctly, but I don't know what's wrong with my hashmap code. It showed everything 0.00. My idea is to find the frequency of each attribute, and compute the ratio based on its frequency and the key. Any help or hint is highly appreciated.
Map<Object, Double> totalCounts = new HashMap<>();
Map<Object, Double> surviveCounts = new HashMap<>();
//put total characteristics in the map
for (Object element : total) {
if (totalCounts.containsKey(element)) {
totalCounts.put(element, totalCounts.get(element) + (double) 1);
} else {
totalCounts.put(element,(double) 1);
}
}
//put survived characteristics in the map
for (Object survive : survival) {
if (surviveCounts.containsKey(survive)) {
surviveCounts.put (survive, surviveCounts.get(survive) + (double) 1);
} else {
surviveCounts.put(survive, (double) 1);
}
}
for (Map.Entry<Object, Double> entrySurvive : surviveCounts.entrySet()) {
Object surviveKey = entrySurvive.getKey();
Double surviveValue = entrySurvive.getValue();
for (Map.Entry<Object, Double> entryTotal : totalCounts.entrySet()) {
Object totalKey = entryTotal.getKey();
Double totalValue = entryTotal.getValue();
if (totalKey.equals(surviveKey)) {
double percent = surviveValue / totalValue;
surviveData.put(surviveKey, percent);
} else {
surviveData.put(totalKey, (double) 0);
}
}
}
//print out the ratio
surviveData.entrySet().stream()
.sorted((k1, k2) -> -k1.getValue().compareTo(k2.getValue()))
.forEach(k -> System.out.println(k.getKey().toString().toLowerCase() + ": " +String.format("%.2f", k.getValue())));
Just update if surviceKey is equal to totalKey
for (Map.Entry<Object, Double> entrySurvive : surviveCounts.entrySet()) {
Object surviveKey = entrySurvive.getKey();
Double surviveValue = entrySurvive.getValue();
for (Map.Entry<Object, Double> entryTotal : totalCounts.entrySet()) {
Object totalKey = entryTotal.getKey();
Double totalValue = entryTotal.getValue();
if (totalKey.equals(surviveKey)) {
double percent = surviveValue / totalValue;
surviveData.put(surviveKey, percent);
}
}
}
Or you can just write,
Map<Object, Double> surviveData = surviveCounts.keySet().stream()
.filter(totalCounts::containsKey)
.collect(
Collectors.toMap(k -> k, k->surviveCounts.get(k)/totalCounts.get(k)));
If using the nested for loop, there is 100% that totalKey and surviveKey will be different. Thus:
for (Map.Entry<Object, Double> entrySurvive : surviveCounts.entrySet()) {
Object surviveKey = entrySurvive.getKey();
Double surviveValue = entrySurvive.getValue();
for (Map.Entry<Object, Double> entryTotal : totalCounts.entrySet()) {
Object totalKey = entryTotal.getKey();
Double totalValue = entryTotal.getValue();
if (totalKey.equals(surviveKey)) {
double percent = surviveValue / totalValue;
surviveData.put(surviveKey, percent);
} else {
//will lead to all attributes' ratio 0.00
surviveData.put(totalKey, (double) 0);
}
}
}
The correct way to put those dead people is:
for (Map.Entry<Object, Double> entrySurvive : surviveCounts.entrySet()) {
Object surviveKey = entrySurvive.getKey();
double surviveValue = entrySurvive.getValue();
for (Map.Entry<Object, Double> entryTotal : totalCounts.entrySet()) {
Object totalKey = entryTotal.getKey();
double totalValue = entryTotal.getValue();
if (totalKey.equals(surviveKey)) {
double percent = surviveValue / totalValue;
surviveData.put(surviveKey, percent);
}
}
}
// if the surviveCounts' keys aren't in the totalCount's key
// it means they're not even survive once
for (Map.Entry<Object, Double> entryTotal : totalCounts.entrySet()) {
Object totalKey = entryTotal.getKey();
if (!surviveCounts.containsKey(entryTotal.getKey())) {
surviveData.put(totalKey, (double) 0);
}
}
Related
public class ProductInStockRequest {
private String productId;
private Integer requestedQuantity;
}
I have a List
requestList.add(new ProductInStockRequest("100", 5));
requestList.add(new ProductInStockRequest("200", 11));
requestList.add(new ProductInStockRequest("300", 33));
requestList.add(new ProductInStockRequest("400", 55));
I have a Map<String, Integer> productInDbMap = new HashMap<>();
productInDbMap.put("100", 10);
productInDbMap.put("200", 10);
productInDbMap.put("300", 44);
productInDbMap.put("400", 77);
I created new Map<String, String> responseMap = new HashMap<>();
I need to go over each element in List and check if for related productId I have enough quantity or not and write result in responseMap
Trying to do something like this:
requestList.stream().map(requestedItem -> {
int quantity = productInDbMap.get(requestedItem.getProductId());
if (quantity >= requestedItem.getRequestedQuantity()) {
responseMap.put(requestedItem.getProductId(), "order-able");
} else {
int availableQuantity = quantity - requestedItem.getRequestedQuantity();
String s = String.valueOf(availableQuantity);
responseMap.put(requestedItem.getProductId(), s);
}
return responseMap;
});
No luck, please advise
you can start with something like this:
Map<String, String> responseMap = requestList.stream().map(requestedItem -> {
int quantity = productInDbMap.get(requestedItem.getProductId());
if (quantity >= requestedItem.getRequestedQuantity()) {
return new AbstractMap.SimpleEntry<>(requestedItem.getProductId(), "order-able");
} else {
int availableQuantity = quantity - requestedItem.getRequestedQuantity();
String s = String.valueOf(availableQuantity);
return new AbstractMap.SimpleEntry<>(requestedItem.getProductId(), s);
}
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
In general, never modify anything from inside the stream or lambdas in general. The compiler will allow it in this case (and will complain in case of modifying a variable), but it's always a bad practice and unsafe.
You can directly collect to map:
Map<String,String> responseMap = requestList.stream()
.collect(Collectors.toMap(ProductInStockRequest::getProductId, requestedItem -> {
int quantity = productInDbMap.get(requestedItem.getProductId());
if (quantity >= requestedItem.getRequestedQuantity()) {
return"order-able";
} else {
int availableQuantity = quantity - requestedItem.getRequestedQuantity();
return String.valueOf(availableQuantity);
}
}));
Your approach will work fine if you use forEach:
Map<String,String> responseMap = new HashMap<>()
requestList.stream()
.forEach(requestedItem -> {
int quantity = productInDbMap.get(requestedItem.getProductId());
if (quantity >= requestedItem.getRequestedQuantity()) {
responseMap.put(requestedItem.getProductId(), "order-able");
} else {
int availableQuantity = quantity - requestedItem.getRequestedQuantity();
String s = String.valueOf(availableQuantity);
responseMap.put(requestedItem.getProductId(), s);
}
});
Pls note that dueTransfersMap lists customer_consignee and it's transfer amounts E.g #cust_ABC , 120
dueTransfersCountMap lists counts for respective customer_consginee. DOUBLE_AT
refers as a delimiter
Map<String, BigDecimal> dueTransfersMap = new HashMap<String, BigDecimal>();
Map<String, Long> dueTransfersCountMap = new HashMap<String, Long>();
BigDecimal dueCustomerConsigneeTransferTotal = BigDecimal.ZERO;
Long dueCustomerConsigneeTransferCount = 1L;
for (DueCustomerAndConsigneeTransferData dueTransferRecord : dueTransferRecordList) {
String sKey = dueTransferRecord.getCustomerName() + Symbol.DOUBLE_AT.getValue() + dueTransferRecord.getConsigneeName();
if (dueTransferRecord.getCustomerConsigneeTransferWeight() != null) {
dueCustomerConsigneeTransferTotal = dueTransferRecord.getCustomerConsigneeTransferWeight();
}
if (dueTransfersMap.containsKey(sKey)) {
dueTransfersMap.put(sKey, dueTransfersMap.get(sKey).add(dueCustomerConsigneeTransferTotal));
dueTransfersCountMap.put(sKey, dueTransfersCountMap.get(sKey) + dueCustomerConsigneeTransferCount);
} else {
dueTransfersMap.put(sKey, dueCustomerConsigneeTransferTotal);
dueTransfersCountMap.put(sKey, dueCustomerConsigneeTransferCount);
}
}
I'm adapting an open source code of Moletrust algorithm implementation from https://github.com/466152112/HappyResearch/blob/master/happyresearch/src/main/java/happy/research/utils/MoleTrust.java
the change that I should make to calculate the trust value is adapted from this paper "Trust-aware Collaborative Filtering for Recommender Systems" written by Moletrust creators. They calculate the trust as follows
"a user at distance n from source user will have a predicted trust value of (d − n + 1)/d" where d is the maximum propagation distance.
The result that I get is either 1 or zero which is not correct. Hope that you can help me find the error.
public static HashMap<String ,Double> MoleTrustAlg ( HashMap<String,HashMap<String,Double>> trust_data,String sourceUser , int horizon)
{
// all the visited nodes
List<String> nodes = new ArrayList<>(40163);
// source user - edges[target users - trust value]
Map<String, Map<String, Double>> edges = new HashMap<>(40163);
/* Step 1: construct directed graphic and remove cyclic */
int dist = 0;
List<String>[] users = new List[horizon + 1];
users[dist] = new ArrayList<>();
users[dist].add(sourceUser);
nodes.add(sourceUser);
// Denote su: source user; tu: target user
while (dist < horizon)
{
dist++;
users[dist] = new ArrayList<>();
for (String su : users[dist - 1])
{
Map<String, Double> tns = trust_data.get(su);
if (tns == null) continue; // no trusted neighbours
for (String tn : tns.keySet())
{
if (!nodes.contains(tn) && !users[dist].contains(tn) && !users[dist - 1].contains(tn))
{
users[dist].add(tn);
}
}
}
for (String su : users[dist - 1])
{
Map<String, Double> tns = trust_data.get(su);
if (tns == null) continue;
for (String tu : tns.keySet())
{
if (!nodes.contains(tu) && users[dist].contains(tu))
{
Map<String, Double> tuTrusts;
if (edges.containsKey(su)) tuTrusts = edges.get(su);
else tuTrusts = new HashMap<>();
double trustValue = tns.get(tu);
tuTrusts.put(tu, trustValue);
edges.put(su, tuTrusts);
}
}
}
}
/* Step 2: Evaluate trust score */
dist = 0;
//double threashold = 0.5;
// trusted neighbours - trust score map
HashMap<String, Double> trustScores = new HashMap<>();
trustScores.put(sourceUser, 1.0);
while (dist < horizon)
{
dist++;
for (String su : users[dist - 1])
{
Map<String, Double> tns = trust_data.get(su);
if (tns == null) continue;
for (String tu : tns.keySet())
{
double trust_value = (horizon -dist +1) / horizon;
trustScores.put(tu, trust_value);
}
}
}
trustScores.remove(sourceUser);
return trustScores;
}
GOT IT
The reason is
double trust_value = (horizon -dist +1) / horizon;
as horizon and dist are integers, I need to cast it before assigning the result to the double variable.
double trust_value = (double) (horizon -dist +1) / horizon;
I have nested map called aMap for which key is a string and value is another map (called y). This y contains strings as key and value. I want to process the values in the nested map and aggregate some of the keys inside y according to some logic (basically I am reducing the number of keys in y). I am able to run my logic using forEach but I need to convert the following using map and collect in Java 8. The problem is I am not sure what to write inside the collect function.
The for each code:
aMap.forEach(
(x, y) -> {
Set<String> remove = new HashSet<>();
Map<String, Double> add = new HashMap<>();
y.forEach(
(key, value) -> {
String z = key;
long b = 0;
try {
b = some_conversion_on_z()
} catch (ParseException e) {
logger.error("Failed to convert", e);
}
if (some_condition_on_b) {
String d = some_conversion_on_z()
Double currCount = value;
Double prevCount = y.get(d);
if (prevCount == null) {
prevCount = 0.0;
add.put(d, prevCount + currCount);
} else {
y.put(d, prevCount + currCount);
remove.add(z);
}
}
});
y.keySet().removeAll(remove);
y.putAll(add);
});
The map-collect that I am trying:
aMap.entrySet()
.map(x -> x.getValue())
.map(y -> y.getKey())
.filter(some_condition_on_y)
.collect(?)
I want to sort some data. At the moment the data is stored in a map. I know, I can't sort data in a map by value. I calculate a soccer schedule like that:
TeamName, G+, G-, P
I want to sort first by P, then by G+, then by G-.
Every k,v is in a map like this:
map.put(e.getString("team_id"), 0);
map.put(e.getString("team_id")+"G+", 0);
map.put(e.getString("team_id")+"G-", 0);
I know that the data structure is really bad! I think it is better to get the values into a Collection to do a collection.sort. But How can I do that?
Here is my code (the code works fine, but is unsorted and badly coded):
HashMap<String, Integer> map = new HashMap<String, Integer>();
HashMap<String, String> tab = new HashMap<String, String>();
for(int i=0; i<teams.length(); i++){
JSONObject e = teams.getJSONObject(i);
//get TeamID
map.put(e.getString("team_id"), 0);
//Goals +
map.put(e.getString("team_id")+"G+", 0);
//Goals -
map.put(e.getString("team_id")+"G-", 0);
//standings.add(map);
//Log.e("Team7", String.valueOf(map.get("7")));
//Log.e("Team7", e.getString("team_id"));
}
for(int i=0; i<matchdata.length(); i++){
JSONObject e = matchdata.getJSONObject(i);
//calculate Points
int myVarGoal1 = Integer.valueOf(e.getString("points_team1"));
int myVarGoal2 = Integer.valueOf(e.getString("points_team2"));
if ((myVarGoal1) > (myVarGoal2)){
myPoint1 = 3;
myPoint2 = 0;
}
if ((myVarGoal1) < (myVarGoal2)){
myPoint1 = 0;
myPoint2 = 3;
}
if ((myVarGoal1) == (myVarGoal2)){
myPoint1 = 1;
myPoint2 = 1;
}
int calc1 = (map.get(e.getString("id_team1")) + myPoint1);
int calc2 = (map.get(e.getString("id_team2")) + myPoint2);
map.put("id", Integer.valueOf(i));
map.put(e.getString("id_team1"), calc1);
map.put(e.getString("id_team2"), calc2);
//calculate Goals
int calcGoal1 = (map.get(e.getString("id_team1")+"G+") + myVarGoal1);
int calcGoal2 = (map.get(e.getString("id_team1")+"G-") + myVarGoal2);
int calcGoal3 = (map.get(e.getString("id_team2")+"G+") + myVarGoal2);
int calcGoal4 = (map.get(e.getString("id_team2")+"G-") + myVarGoal1);
map.put(e.getString("id_team1")+"G+", calcGoal1);
map.put(e.getString("id_team1")+"G-", calcGoal2);
map.put(e.getString("id_team2")+"G+", calcGoal3);
map.put(e.getString("id_team2")+"G-", calcGoal4);
//standings.add(map);
//Log.e("TeamID", e.getString("id_team1"));
//Log.e("PointsTeam7", String.valueOf(map.get("7")));
//Log.e("GaolsTeam7", String.valueOf(map.get("7G-")));
}
for(int i=0; i<teams.length(); i++){
JSONObject e = teams.getJSONObject(i);
String myTeamID = e.getString("team_id");
int Gdif = (map.get(myTeamID+"G+")) - (map.get(myTeamID+"G-"));
tab.put(myTeamID, e.getString("team_name") +","+ map.get(myTeamID) +","+ (map.get(myTeamID+"G+")) +":"+ (map.get(myTeamID+"G-")) +" "+ Gdif);
//Log.e("Team7", String.valueOf(tab.get("7")));
//Log.e("Team7", e.getString("team_id"));
strGoals+="\n" + String.valueOf(tab.get(myTeamID));
}
It sounds like you need to first create your own class to hold related data as one single object. The exact name of the class depends on what the data is. Maybe SoccerTeam or SoccerSchedule. After you create this class, you can implement the Comparable interface or create a Comparator object that defines the sorting order.
I think what you're looking for is a TreeMap and a Comparator. Can you switch to using a TreeMap instead? It works just like a HashMap, but will automatically sort your keys for you. Then you can use a Comparator like this:
Map<String, Integer> map = new HashMap<String, Integer>();
..... do stuff .....
TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>(new Comparator<String>()
{
#Override
public int compare(String lhs, String rhs)
{
// return 1 if lhs > rhs
// return 0 if lhs = rhs
// return -1 if lhs < rhs
if (lhs == null && rhs == null) return 0;
if (lhs == null) return -1;
if (rhs == null) return 1;
if ((lhs.endsWith("P") && (rhs.endsWith("P")))
|| (lhs.endsWith("G+") && (rhs.endsWith("G+")))
|| (lhs.endsWith("G-") && (rhs.endsWith("G-"))))
{
return lhs.compareTo(rhs);
}
else if (lhs.endsWith("P"))
{
return -1;
}
else if (rhs.endsWith("P"))
{
return 1;
}
else
{
String lastLeftChar = lhs.substring(lhs.length()-1);
String lastRightChar = rhs.substring(rhs.length()-1);
return lastLeftChar.compareTo(lastRightChar);
}
}
});
treeMap.putAll(map);
// Now your treeMap is sorted by the keys!