Pick objects that contain all or one but not more? - java

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

Related

Stream API - need to iterate over the List and compare with Map. Write result in different Map

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);
}
});

Promotion progression logic

i have list of items in cart(assume each letter is an item)
cart list = a,s,d,f,a,s,d,f,a
here is the promotion
buy 1 a and get 2 d Free of Charge(in the below logic 1 is srcNum and 2 is tarNum)
the logic should be progressive.(for each a 2d should be free).
for the above input o/p should be d,d
i made some thing like below. but not working
any help appreciated
Iterator tempIterator = tempList.iterator();
boolean targetCheck = false;
int check=0;
boolean runCompleted = false;
while (!runCompleted && tempIterator.hasNext()){
String itemCode = (String) tempIterator.next();
if(!targetCheck && targetItemsList.contains(itemCode) && check < tarNum){
tempIterator.remove();
check++;
}
else if (check >= tarNum && targetCheck == false) {
check = 0;
targetCheck = true;
}
else if (check < srcNum && targetCheck == true) {
tempIterator.remove();
Integer discountQuantity = discountedItems.get(itemCode);
if(null==discountQuantity) {
discountQuantity = 1;
}else {
discountQuantity++;
}
discountedItems.put(itemCode,discountQuantity);
check++;
}
else if (check >= srcNum && targetCheck == true) {
check = 0;
targetCheck = false;
}
if(tempList.size()==0){
runCompleted = true;
}else{
tempIterator = tempIterator = tempList.iterator();
}
Your discount must be stored: item a has 2 d free. Since java 9 you can use the record class.
record Discount(int itemCode, int free) {};
Map<Integer, Discount> itemCodeToDiscountMap = new HashMap<>();
This becomes a bit more complex if 2 a 1 d free or even 2 a 1 a free. But not unduly.
You have a chaotic cart, something like:
List<Item> cartList = new ArrayList<>();
This is best kept in a map of item code to quantity.
Map<Integer, Integer> itemCodeToQuantityMap = new HashMap<>();
At the end of your evaluation you will have:
Map<Integer, Integer> itemsToPay = new HashSet<>();
Map<Integer, Integer> itemsFree = new HashSet<>();
Map<Integer, Integer> itemsCouldTakeFree = new HashSet<>();
So [a, a, b, d, d, d] with 1a=2d free:
itemsToPay = [a -> 2, b -> 1]
itemsFree = [d -> 3]
itemsCouldTakeFree = [d -> 1] "You can fetch 1 d free"
The first step, simplifying the cart data:
List<Item> cartList = new ArrayList<>();
...
Map<Integer, Integer> itemCodeToQuantityMap = new HashMap<>();
for (Item item: cartList) {
Item oldItem = itemCodeToQuantityMap.get(item.itemCode);
...
itemCodeToQuantityMap.get(item.itemCode, ...);
}
And then
itemsToPay.putAll(itemCodeToQuantityMap);
for (Map.Entry<Integer, Integer> entry: itemCodeToQuantityMap.entrySet()) {
int itemCode = entry.getKey();
int quantity = entry.getValue();
Discount discount = itemCodeToDiscountMap.get(itemCode);
...
}
First making a copy of itemCodeToQuantityMap into itemsToPay means you need not alter itemCodeToQuantityMap but can discount in / subtract from itemsToPay.
As this reeks of home work, I leave it at that. Just the tips:
Use data structures easying the work; here having the quantity of every item.
So one needs a Map.

Iterating through a HashMap until the first value is found?

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!");
}

Group HashMap items according to a specific key

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.

Jfreechart: how to get the individual items in a BoxAndWhiskerChart

I am generating a box and whisker chart with one item per category.I also want to generate a report with the mean, median and all the values per item in the BoxPlot. So, after i create the dataset, defaultboxandwhiskercategorydataset based on the categoryType, I call the method convertReportData to fetch each item in the defaultboxandwhiskercategorydataset and save the mean, median etc into another data object later for report generation. But it just prints only one category. Could anyone please help me to figure out what is wrong?
My boxplot
Code:
public static BoxAndWhiskerCategoryDataset createDataset() {
startTime = inputData.getItimeFrom();
endTime = inputData.getItimeTo();
List<String> categorylist = new ArrayList<>();
categorylist.add("Distance 0-20");
categorylist.add("Distance 20-40");
categorylist.add("Distance 40-60");
categorylist.add("Distance 60-80");
categorylist.add("Distance 80-100");
categorylist.add("Distance >100");
Map<String, List<Double>> map = new HashMap<String, List<Double>>();
map = addDistance(values_list);
DefaultBoxAndWhiskerCategoryDataset defaultboxandwhiskercategorydataset = new DefaultBoxAndWhiskerCategoryDataset();
for (String categoryType : categorylist) {
map.remove(null);
for (Map.Entry<String, List<Double>> entry : map.entrySet()) {
if (entry.getKey().equalsIgnoreCase(categoryType)) {
defaultboxandwhiskercategorydataset.add(entry.getValue(),
categoryType, " ");
}
}
}
convertReportData(defaultboxandwhiskercategorydataset, categorylist);
return defaultboxandwhiskercategorydataset;
}
private static void convertReportData(DefaultBoxAndWhiskerCategoryDataset boxandwhiskercategorydataset, List<String> latencyTypelist) {
report = new HashMap<>();
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
BoxAndWhiskerItem item = boxandwhiskercategorydataset.getItem(i, 0);
ReportData data = new ReportData();
data.setMean(item.getMean());
data.setMedian(item.getMedian());
data.setQ1(item.getQ1());
data.setQ3(item.getQ3());
data.setMaxOutlier(item.getMaxOutlier());
data.setMaxRegularNumber(item.getMaxRegularValue());
data.setMinOutlier(item.getMinOutlier());
data.setMinRegularNumber(item.getMinRegularValue());
data.setOutliers(item.getOutliers());
report.put(boxandwhiskercategorydataset.getRowKey(i).toString(),
data);
}
}
The problem is with
for (int i = 0; i < boxandwhiskercategorydataset.getColumnKeys().size(); i++) {
you are using getColumnKeys whereas you have only one Column. It should have been,
for (int i = 0; i < boxandwhiskercategorydataset.getRowKeys().size(); i++) {

Categories

Resources