如何从TreeMap中随机获取键值对并移除后重复操作?
问题描述
我需要从TreeMap中随机获取一个键值对,通过随机生成器选中键并展示对应的值。这个TreeMap的键是字符串类型,值是double类型,比如myMap.put("CanSoupWt", 1.0)。
我是Java编程新手,写的代码比较繁琐,想要实现的逻辑是:从TreeMap里随机取出一组键值对,移除它之后,对剩下的TreeMap重复这个操作,直到达到重量限制。
以下是我尝试的代码:
package traditional_pantry_sep08_2022; import java.util.ArrayList; import java.util.TreeMap; import java.util.List; import java.util.Map; import java.util.Random; public class Main2 { public static void main(String[] args) { // 选择优先级最高的罐头食品 double v_Can_Soup_Wt = 0.95; double v_Can_Peas_Wt = 0.95; double v_Can_Mix_Wt = 0.95; double v_Can_Meat_Wt = 0.95; double v_Can_Corn_Wt = 0.95; double v_Can_Green_Wt = 0.95; double v_Can_Veggies_Wt = 0.95; double v_Can_Apple_Wt = 0.95; double v_Can_Soup_Qty = 0; double v_Can_Peas_Qty = 0; double v_Can_Mix_Qty = 0; double v_Can_Meat_Qty = 0; double v_Can_Corn_Qty = 0; double v_Can_Green_Qty = 0; double v_Can_Veggies_Qty = 0; double v_Can_Apple_Qty = 0; double household = 2; double v_Can_Tot_Wt = 0; // 根据家庭人数设置罐头总重量上限 double v_Can_Tot_MaxWt = 14 + (4 * (household -1)); // 根据家庭人数设置每种罐头的最大数量 double v_Can_Soup_MaxQty = 5 + (2 * (household - 1)); double v_Can_Peas_MaxQty = 5 + (2 * (household - 1)); double v_Can_Mix_MaxQty = 5 + (2 * (household - 1)); double v_Can_Meat_MaxQty = 5 + (2 * (household - 1)); double v_Can_Corn_MaxQty = 5 + (2 * (household - 1)); double v_Can_Green_MaxQty = 5 + (2 * (household - 1)); double v_Can_Veggies_MaxQty = 5 + (2 * (household - 1)); double v_Can_Apple_MaxQty = 5 + (2 * (household - 1)); // 随机选择罐头直到达到重量上限 // 将罐头重量存入TreeMap TreeMap<String, Double> canall = new TreeMap<String, Double>(); canall.put("CanSoupWt", v_Can_Soup_Wt); canall.put("CanPeasWt", v_Can_Peas_Wt); canall.put("CanMixWt", v_Can_Mix_Wt); canall.put("CanMeatWt", v_Can_Meat_Wt); canall.put("CanCornWt", v_Can_Corn_Wt); canall.put("CanGreenWt", v_Can_Green_Wt); canall.put("CanVeggiesWt", v_Can_Veggies_Wt); canall.put("CanAppleWt", v_Can_Apple_Wt); // 打印TreeMap System.out.println("The TreeMap is : " + canall); // 从TreeMap中随机选择一个罐头 do { Object[] crunchifyKeys = canall.keySet().toArray(); Object key = crunchifyKeys[new Random().nextInt(crunchifyKeys.length)]; System.out.println("************ Random Value ************\n" + key + " :: " + canall.get(key)); List<Map.Entry<String, Double>> list = new ArrayList<Map.Entry<String, Double>>(canall.entrySet()); System.out.println("The TreeMap is : " + canall); // 选取最大数量的罐头 if (key == "CanSoupWt") { do { v_Can_Soup_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Soup_Wt * v_Can_Soup_Qty); } while (v_Can_Soup_Qty < v_Can_Soup_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Soup_Qty--; } canall.remove("CanSoupWt"); // 移除已选项目 } else if (key == "CanPeasWt") { do { v_Can_Peas_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Peas_Wt * v_Can_Peas_Qty); } while (v_Can_Peas_Qty < v_Can_Peas_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Peas_Qty--; } canall.remove("CanPeasWt"); // 移除已选项目 } else if (key == "CanMixWt") { do { v_Can_Mix_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Mix_Wt * v_Can_Mix_Qty); } while (v_Can_Mix_Qty < v_Can_Mix_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Mix_Qty--; } canall.remove("CanMixWt"); // 移除已选项目 } else if (key == "CanMeatWt") { do { v_Can_Meat_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Meat_Wt * v_Can_Meat_Qty); } while ( v_Can_Meat_Wt < v_Can_Meat_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Meat_Qty--; } canall.remove("CanMeatWt"); // 移除已选项目 } else if (key == "CanCornWt") { do { v_Can_Corn_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Corn_Wt * v_Can_Corn_Qty); } while (v_Can_Corn_Wt < v_Can_Corn_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Corn_Qty--; } canall.remove("CanCornWt"); // 移除已选项目 } else if (key == "CanGreenWt") { do { v_Can_Green_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Green_Wt * v_Can_Green_Qty); } while (v_Can_Green_Wt < v_Can_Green_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Green_Qty--; } canall.remove("CanGreenWt"); // 移除已选项目 } else if (key == "CanVeggiesWt") { do { v_Can_Veggies_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Veggies_Wt * v_Can_Veggies_Qty); } while (v_Can_Veggies_Wt < v_Can_Veggies_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Veggies_Qty--; } canall.remove("CanVeggiesWt"); // 移除已选项目 } else if (key == "CanAppleWt") { do { v_Can_Apple_Qty++; v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Apple_Wt * v_Can_Apple_Qty); } while (v_Can_Apple_Wt < v_Can_Apple_MaxQty /*&& v_Can_Tot_Wt < v_Can_Tot_MaxWt*/); if (v_Can_Tot_Wt > v_Can_Tot_MaxWt) { v_Can_Apple_Qty--; } canall.remove("CanAppleWt"); // 移除已选项目 } v_Can_Tot_Wt = (v_Can_Soup_Wt * v_Can_Soup_Qty) + (v_Can_Peas_Wt * v_Can_Peas_Qty) + (v_Can_Mix_Wt * v_Can_Mix_Qty) + (v_Can_Meat_Wt * v_Can_Meat_Qty) + (v_Can_Corn_Wt * v_Can_Corn_Qty)+ (v_Can_Green_Wt * v_Can_Green_Qty) + (v_Can_Veggies_Wt * v_Can_Veggies_Qty) + (v_Can_Apple_Wt * v_Can_Apple_Qty); } while (v_Can_Tot_Wt < v_Can_Tot_MaxWt); System.out.println("Household Members: " +household); System.out.println("Can Soup Qty: " +v_Can_Soup_Qty); System.out.println("Can Peas Qty: " +v_Can_Peas_Qty); System.out.println("Can Mix Beans Qty: " +v_Can_Mix_Qty); System.out.println("Can Meat Qty: " +v_Can_Meat_Qty); System.out.println("Can Corn Qty: " +v_Can_Corn_Qty); System.out.println("Can Green Qty: " +v_Can_Green_Qty); System.out.println("Can Veggies Qty: " +v_Can_Veggies_Qty); System.out.println("Can Apple Qty: " +v_Can_Apple_Qty); System.out.println("Can Food Total Weight: " +v_Can_Tot_Wt); System.out.println("Can Food Maximum Weight: " +v_Can_Tot_MaxWt); // 打印TreeMap System.out.println("The TreeMap is : " + canall); } }
关键问题与优化方案
1. 字符串比较错误
原代码用key == "CanSoupWt"比较字符串,Java中==比较的是对象引用地址,不是内容,必须用"CanSoupWt".equals(key)才能正确判断字符串相等,否则会出现逻辑失效的问题。
2. 重复代码冗余
大量重复的if-else逻辑可以用Map存储罐头的数量和最大值,避免冗余的循环和判断,大幅简化代码。
3. Random对象复用
每次循环新建Random对象既浪费资源,还会影响随机性,建议提前创建一个全局的Random实例重复使用。
4. 重量计算逻辑错误
原代码内部do-while循环的重量计算有误:v_Can_Tot_Wt = v_Can_Tot_Wt + (v_Can_Soup_Wt * v_Can_Soup_Qty)会重复累加之前的数量,正确的应该是每次加单个罐头的重量:v_Can_Tot_Wt += v_Can_Soup_Wt。
5. 随机访问效率优化
每次从TreeMap的keySet转数组效率较低,可以提前把键存入List,直接通过随机索引访问,移除时同时操作List和TreeMap。
优化后的代码示例
package traditional_pantry_sep08_2022; import java.util.*; public class Main2 { public static void main(String[] args) { // 罐头重量配置 Map<String, Double> canWeights = new HashMap<>(); canWeights.put("CanSoup", 0.95); canWeights.put("CanPeas", 0.95); canWeights.put("CanMix", 0.95); canWeights.put("CanMeat", 0.95); canWeights.put("CanCorn", 0.95); canWeights.put("CanGreen", 0.95); canWeights.put("CanVeggies", 0.95); canWeights.put("CanApple", 0.95); // 存储每种罐头的数量 Map<String, Integer> canQuantities = new HashMap<>(); for (String canType : canWeights.keySet()) { canQuantities.put(canType, 0); } double household = 2; double totalWeight = 0; double maxTotalWeight = 14 + (4 * (household - 1)); int maxPerCan = 5 + (2 * (int)(household - 1)); // 初始化可选择的罐头列表 List<String> availableCans = new ArrayList<>(canWeights.keySet()); Random random = new Random(); // 随机选择直到达到重量上限或无罐头可选 while (totalWeight < maxTotalWeight && !availableCans.isEmpty()) { // 随机选一个罐头类型 int randomIndex = random.nextInt(availableCans.size()); String selectedCan = availableCans.get(randomIndex); double weightPerCan = canWeights.get(selectedCan); System.out.printf("************ 随机选中 ************\n%s :: %.2f\n", selectedCan, weightPerCan); // 计算能加的最大数量 int currentQty = canQuantities.get(selectedCan); int addQty = 0; while (currentQty + addQty < maxPerCan) { double newWeight = totalWeight + weightPerCan * (addQty + 1); if (newWeight > maxTotalWeight) { break; } addQty++; } // 更新数量和总重量 canQuantities.put(selectedCan, currentQty + addQty); totalWeight += weightPerCan * addQty; // 移除已选罐头 availableCans.remove(randomIndex); System.out.println("当前总重量: " + totalWeight); } // 输出结果 System.out.println("\n家庭人数: " + household); for (Map.Entry<String, Integer> entry : canQuantities.entrySet()) { System.out.printf("%s 数量: %d\n", entry.getKey(), entry.getValue()); } System.out.println("罐头总重量: " + totalWeight); System.out.println("罐头最大重量限制: " + maxTotalWeight); } }
内容的提问来源于stack exchange,提问作者Ben Morrow
相关产品推荐
相关产品推荐

