I have a HashMap that I have used to store an integer id and an String value.
I wanted to be able to remove things from the HashMap based off of a user input String. The way I have been doing that is as followed:
public void pickingVehicleUp() {
System.out.println("Please enter number plate: ");
input = new Scanner(System.in);
String PLATE = input.nextLine();
Iterator<Map.Entry<Integer, String>> iter = zone_1.entrySet().iterator();
Map.Entry<Integer, String> Empty1 = iter.next();
Map.Entry<Integer, String> Empty2 = iter.next();
Map.Entry<Integer, String> Empty3 = iter.next();
Map.Entry<Integer, String> Empty4 = iter.next();
Map.Entry<Integer, String> Empty5 = iter.next();
zone_1.entrySet().removeIf(entry -> (PLATE.equals(entry.getValue())));
if (Empty1.getValue().equals(PLATE)) {
Integer key = Empty1.getKey();
zone_1.put(key, "Empty");
} else if (Empty2.getValue().equals(PLATE)) {
Integer key = Empty2.getKey();
zone_1.put(key, "Empty");
} else if (Empty3.getValue().equals(PLATE)) {
Integer key = Empty3.getKey();
zone_1.put(key, "Empty");
} else if (Empty4.getValue().equals(PLATE)) {
Integer key = Empty4.getKey();
zone_1.put(key, "Empty");
} else if (Empty5.getValue().equals(PLATE)) {
Integer key = Empty5.getKey();
zone_1.put(key, "Empty");
} else {
System.out.println("That number plate doesn't exist!");
}
}
While this code works fine, I think that it is very untidy and there are probably much more efficient ways to do it and i'd like to find one of those ways as I need to do this same method for 5 different HashMaps.
May be something like this would help you
String PLATE = "PLATE";
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "DOOR");
map.put(2, "DOG");
map.put(3, "PLATE");
map.put(4, "SNOW");
System.out.println("Before check - " + map);
if (map.containsValue(PLATE)) {
for (Map.Entry<Integer, String> item:map.entrySet()) {
if (item.getValue().equals(PLATE)) {
map.remove(item.getKey());
break;
}
}
}
System.out.println("After check - " + map);
It would probably be easier if you reversed the Map as JB Nizet suggests in the comments. Intuitively, if you are looking for Plate and where it is located, it makes more sense for your Map to store parking space ID as a function of Plate number. Then it makes your task trivial:
String PLATE = "PLATE1";
Map<String, Integer> plateToParkingSpaceID = new HashMap<>();
plateToParkingSpaceID.put("PLATE1", 1);
plateToParkingSpaceID.put("PLATE2", 2);
plateToParkingSpaceID.put("PLATE3", 3);
plateToParkingSpaceID.put("PLATE4", 4);
if (plateToParkingSpaceID.containsKey(PLATE)) {
plateToParkingSpaceID.remove(PLATE);
} else {
System.out.println("That number plate doesn't exist!");
}
However, if you keep you current design of mapping the parking space to the license place, we can do the following:
String PLATE = "PLATE1";
Optional<Integer> parkingSpaceId = zone1.entrySet().stream() // stream all of the entries in the zone1 Map
.filter(e -> e.getValue().equals()) // filter out all that don't have the correct plate
.findFirst() // there should be 0 or 1 of these, so we can stop as soon as we find the first one
if (parkingSpaceId.isPresent()) {
zone1.remove(parkingSpaceId.get()); // remove that space from the map
} else {
System.out.println("That number plate doesn't exist!");
}
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);
}
}
So I have an object(Drink) with a Map of ingredients and I want to go through a List of them.
I would like to find any Drink that as only the ingredients I search for, and not ones that have any other ingredients.
drinkA.ingredients("water","sugar","salt")
drinkB.ingredients("sugar","salt")
drinkC.ingredients("water")
drinkD.ingredients("sugar")
drinkE.ingredients("salt")
drinkF.ingredients("water","sugar")
drinkG.ingredients("water","salt")
So if I search for water and salt I want to see
drinkC
drinkE
drinkG
This is what I have but it only gives me Drinks with the ingredients I've searched for and more.
public void findSearchResults(String searchRegex, Gui gui) {
if(searchRegex.equals("") || searchRegex == null){
return;
}
List<String> multiSearch = new ArrayList<String>();
if(searchRegex.contains(",")){
multiSearch = Arrays.asList(searchRegex.split(","));
}else{
multiSearch.add(searchRegex);
}
int originSize = multiSearch.size();
gui.drinksToDisplay = new ArrayList<Drink>();
for(Drink d : allDrinks){
int regexIn = 0;
List<String> tempStrs = new ArrayList<String>();
tempStrs.addAll(multiSearch);
if(gui.searchStyle.equals("Has only Ingredients")){
Map<String, String> ingreds = d.getIngredients();
Set<Entry<String, String>> ingredsSet = ingreds.entrySet();
Iterator<Entry<String, String>> ingredsIter = ingredsSet.iterator();
while(ingredsIter.hasNext()){
Entry<String, String> e = ingredsIter.next();
for(String s : tempStrs){
if(e.getKey().toLowerCase().contains(s.toLowerCase())){
tempStrs.remove(s);
regexIn++;
break;
}
}
if(regexIn == originSize && tempStrs.isEmpty()){
gui.drinksToDisplay.add(d);
break;
}
}
}
}
}
edit: I added some more code and a little more information on what I want to acomplish
I have a ArrayList>> which holds certain key-value entries. Like:-
ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String,String>>();
HashMap<String,String> map = new HashMap<String,String>();
map.put("NewId", newId);
map.put("Title", title);
map.put("Description", description);
myList.add(map);
"NewId" can be similar for multiple entries.
Also I have an Array of colors:-
String[] colors = new String[]{"#1F1A17", "#62934D", "#F9B03F", "#7959BC", "#74B8DE", "#E65641", "#7CC8BB", "#D7CE5D", "#D6BE95", "#B694D1"};
I want to now group all the entries with same "NewId" together and assign them the first color, other entries with next similar "NewId" with the second color and so on till items with first 10 same "NewId" get assigned with their respective colors.
eg:- before grouping
NewId Title Description
101 title1 des1
102 title2 des2
103 title3 des3
101 title4 des4
102 title5 des5
103 title6 des6
after grouping
NewId Title Description
101 title1 des1 ------> color1
101 title4 des4 ------> color1
102 title2 des2 ------> color2
102 title5 des5 ------> color2
103 title3 des3 ------> color3
103 title6 des6 ------> color3
How can I achieve this?
You're going to need a pretty impressive loop. Advanced for loops are really going to help. If I understand you right, you want something like this
int i = 0; //Or whatever the starting id number is
int j = 0; //For managing the color assigning
//If you want a new hash map Map<String, String> colorsMap = new HashMap<>();
for (HashMap<String, String> loopMap : myList) {
while (i < colors.length) {
if (loopMap.containsKey("" + i) {
loopMap.put("" + i + "color", colors[j]);
//Or if you want to make a new HashMap: colorsMap.put("" + i, colors[j]);
}
i++; //Now start with next id entry
j++; //And next color
}
i = 0; //Or starting id num
j = 0; //Starting color index
}
//If you are making a new hash map: myList.add(colorsMap);
I would personally use a class to put the data, title, description, and color data together, it will make things a lot simpler. And it would let you add methods to better
you can add a custom list class:
public class MyList {
private ArrayList<HashMap<String, String>> list = new ArrayList<>();
public boolean add(HashMap<String, String> map) {
return list.add(map);
}
public void setColor(String newId, String color) {
for (HashMap<String, String> m : list)
if (m.containsKey(newId))
m.put("color", color);
}
public String getGroupKey(String key, int i) {
ArrayList<String> uniqeList = getUniqKeyList(key);
Collections.sort(uniqeList);
return uniqeList.get(i);
}
public ArrayList<String> getUniqKeyList(String key){
ArrayList<String> l = new ArrayList<>();
for (HashMap<String, String> m : list)
if(!l.contains(m.get(key)))
l.add(m.get(key));
return l;
}
}
and in main every thing is clear and simple :
public static void main(String[] args) throws Exception {
MyList myList = new MyList();
HashMap<String,String> map = new HashMap<String,String>();
map.put("NewId", newId);
map.put("Title", title);
map.put("Description", description);
myList.add(map);
String[] colors = new String[]{"#1F1A17", "#62934D","#B694D1"};
int i=0;
while (true) {
if(i == colors.length)
break;
String s = myList.getGroupKey("NewId", i);
if(s == null)
break;
else
myList.setColor(s, colors[i++]);
}
}
I would suggest, instead of using an Arraylist<HashMap<string, string>> you use a HashMap<string, List<MyCustomObject>>. The CustomObject class will hold attributes NewId, Title and Description. The Key for this hashmap is the NewId attribute. This is important because you are assigning colors per value for NewId. Using this approach, you can assign one color per entry in your map.
In java, I want to compare two maps, like below, do we have existing API to do this ?
Thanks
Map<String, String> beforeMap ;
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap ;
afterMap.put("a", "1");
afterMap.put("c", "333");
//--- it should give me:
b is missing, c value changed from '3' to '333'
I'd use removeAll() functionality of Set to to do set differences of keys to find additions and deletions. Actual changes can be detected by doing a set difference using the entry set as HashMap.Entry implements equals() using both key and value.
Set<String> removedKeys = new HashSet<String>(beforeMap.keySet());
removedKeys.removeAll(afterMap.keySet());
Set<String> addedKeys = new HashSet<String>(afterMap.keySet());
addedKeys.removeAll(beforeMap.keySet());
Set<Entry<String, String>> changedEntries = new HashSet<Entry<String, String>>(
afterMap.entrySet());
changedEntries.removeAll(beforeMap.entrySet());
System.out.println("added " + addedKeys);
System.out.println("removed " + removedKeys);
System.out.println("changed " + changedEntries);
Output
added []
removed [b]
changed [c=333]
The Guava Maps class has some methods for calulating the differences between a pair of maps. However, these methods give you a data structure representing the differences not a pretty-printed string.
There isn't any out of the box component to help with that. You'll probably have to code it unfortunately. The good news is the logic is pretty easy.
Depending upon your particular needs, you might also consider using other applications designed to do this work, like diff. You could write the two maps to two different files, and diff the files.
String output = new String();
for (String key:beforeMap.getKeys()){
String beforeValue = beforeMap.getValue(key);
String afterValue = afterMap.getValue(key);
//nullsafe
if(beforeValue.equals(afterValue){}
else if (afterValue == null){
output = output + key + " is missing, ";
continue;
}else {
output = output + key + " has changed from " + beforeValue + " to " + afterValue + " , ";
}
afterMap.remove(key);
}
for (String key:afterMap.getKeys()){
output = output + key + " was added with value " + afterMap.getValue(key) + ", ";
}
if(output == null){
output = "Same map";
}
output = output.substring(0,output.length-2);
System.out.println(output);
You could use a custom object that contains the key and the value (actually Map does this internally, hidden from the user, so we can't use that)
Put these tuples into a Set
To compare two sets, convert them both to arrays, sort the arrays and walk both arrays from begin to end in parallel, stepping down the first array if it's key is smaller than the key in the second array, and vise versa.
class Tuple implements Comparable<Tuple>
{
public String key;
public String value;
public Tuple(String key, String value)
{
this.key = key;
this.value = value;
}
#Override
public int compareTo(Tuple o)
{
return key.compareTo(o.key);
}
}
public static void main(String[] args)
{
// TreeSet is already sorted. If you use HashSet, use Arrays.sort()
Set<Tuple> beforeSet = new TreeSet<>();
beforeSet.add(new Tuple("a", "1"));
beforeSet.add(new Tuple("b", "2"));
beforeSet.add(new Tuple("c", "4"));
Set<Tuple> afterSet = new TreeSet<>();
afterSet.add(new Tuple("a", "1"));
afterSet.add(new Tuple("c", "333"));
afterSet.add(new Tuple("aa", "4"));
Tuple[] beforeArray = beforeSet.toArray(new Tuple[beforeSet.size()]);
Tuple[] afterArray = afterSet.toArray(new Tuple[afterSet.size()]);
int beforePtr = 0;
int afterPtr = 0;
while (beforePtr < beforeArray.length || afterPtr < afterArray.length)
{
int difference = afterPtr >= afterArray.length? -1 : beforePtr >= beforeArray.length? 1 : beforeArray[beforePtr].compareTo(afterArray[afterPtr]);
if (difference == 0)
{
if (!beforeArray[beforePtr].value.equals(afterArray[afterPtr].value))
{
System.out.println(beforeArray[beforePtr].key + " value changed from '" + beforeArray[beforePtr].value + "' to '" + afterArray[afterPtr].value + "'");
}
beforePtr++;
afterPtr++;
}
else if (difference < 0)
{
System.out.println(beforeArray[beforePtr].key + " is missing");
beforePtr++;
}
else
{
System.out.println(afterArray[afterPtr].key + " is added");
afterPtr++;
}
}
}
#user595234 To Compare the two Maps you can add the keys of a map to list and with those 2 lists you can use the methods retainAll() and removeAll() and add them to another common keys list and different keys list. Using the keys of the common list and different list you can iterate through map, using equals you can compare the maps.
public class Demo
{
public static void main(String[] args)
{
Map<String, String> beforeMap = new HashMap<String, String>();
beforeMap.put("a", "1");
beforeMap.put("b", "2");
beforeMap.put("c", "3");
Map<String, String> afterMap = new HashMap<String, String>();
afterMap.put("a", "1");
afterMap.put("c", "333");
System.out.println("Before "+beforeMap);
System.out.println("After "+afterMap);
List<String> beforeList = getAllKeys(beforeMap);
List<String> afterList = getAllKeys(afterMap);
List<String> commonList1 = beforeList;
List<String> commonList2 = afterList;
List<String> diffList1 = getAllKeys(beforeMap);
List<String> diffList2 = getAllKeys(afterMap);
commonList1.retainAll(afterList);
commonList2.retainAll(beforeList);
diffList1.removeAll(commonList1);
diffList2.removeAll(commonList2);
System.out.println("Common List of before map "+commonList1);
System.out.println("Common List of after map "+commonList2);
System.out.println("Diff List of before map "+diffList1);
System.out.println("Diff List of after map "+diffList2);
if(commonList1!=null & commonList2!=null) // athough both the size are same
{
for (int i = 0; i < commonList1.size(); i++)
{
if ((beforeMap.get(commonList1.get(i))).equals(afterMap.get(commonList1.get(i))))
{
System.out.println("Equal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
else
{
System.out.println("Unequal: Before- "+ beforeMap.get(commonList1.get(i))+" After- "+afterMap.get(commonList1.get(i)));
}
}
}
if (CollectionUtils.isNotEmpty(diffList1))
{
for (int i = 0; i < diffList1.size(); i++)
{
System.out.println("Values present only in before map: "+beforeMap.get(diffList1.get(i)));
}
}
if (CollectionUtils.isNotEmpty(diffList2))
{
for (int i = 0; i < diffList2.size(); i++)
{
System.out.println("Values present only in after map: "+afterMap.get(diffList2.get(i)));
}
}
}
/** getAllKeys API adds the keys of the map to a list */
private static List<String> getAllKeys(Map<String, String> map1)
{
List<String> key = new ArrayList<String>();
if (map1 != null)
{
Iterator<String> mapIterator = map1.keySet().iterator();
while (mapIterator.hasNext())
{
key.add(mapIterator.next());
}
}
return key;
}
}
The below code will give you this output:
Before: {b=2, c=3, a=1}
After: {c=333, a=1}
Unequal: Before- 3 After- 333
Equal: Before- 1 After- 1
Values present only in before map: 2