[英]Check if elements in List are valid and in the right order
I am making a replica of a Subway restaurant where you would receive an order in a certain sequence and check if the sequence is valid and if the ingredients are in the menu.我正在制作 Subway 餐厅的复制品,您将在其中按特定顺序收到订单,并检查该顺序是否有效以及菜单中是否有食材。
The right order is: 1 bread, 0 to 1 meat, 1 cheese, 1 to 3 extras, 1 to 3 sauces.正确的顺序是:1 块面包、0 到 1 块肉、1 块奶酪、1 到 3 份额外食物、1 到 3 种酱汁。
Meaning that an order can have a minimum of 4 ingredients (bread, cheese, 1 extra, 1 sauce) and a maximum of 9 ingredients (bread, meat, cheese, 3 extras, 3 sauces).这意味着一个订单可以包含至少 4 种成分(面包、奶酪、1 种额外成分、1 种酱汁)和最多 9 种成分(面包、肉类、奶酪、3 种额外成分、3 种酱汁)。
My question is if there is a more optimized/smarter method to go about validating each and every ingredient than mine?我的问题是,是否有比我的更优化/更智能的方法来验证每种成分?
Code:代码:
// Example order
HashMap<String, HashSet<String>> menu = new HashMap<>();
public static void main(String[] args) {
// Example order
List<String> ingredients = Arrays.asList("Wheat", "Veal",
"Yellow", "Cucumbers", "Onions");
if (!isValid(ingredients)) {
// throw exc;
}
boolean isValid(List<String> ingredients) {
if (ingredients.size() < 4 || ingredients.size() > 9) {
return false;
}
int i = 0;
// Bread
if (!Restaurant.menu.get("Bread")
.contains(ingredients.get(i++))) {
System.out.println("Bread");
return false;
}
// Meat
if (!(Restaurant.menu.get("Meat")
.contains(ingredients.get(i)))
&& !Restaurant.menu.get("Cheese")
.contains(ingredients.get(i))) {
System.out.println("Meat");
return false;
}
if (Restaurant.menu.get("Meat")
.contains(ingredients.get(i))) { // Meat case
if ((!Restaurant.menu.get("Cheese")
.contains(ingredients.get(++i)))) {
System.out.println("Cheese");
return false;
}
}
for (int j = ++i; j < ingredients.size(); j++) {
if ((!Restaurant.menu.get("Extras")
.contains(ingredients.get(j)))) { // Extras
if (j == i) {
return false;
} else {
if ((!Restaurant.menu.get("Sauces")
.contains(ingredients.get(j)))) { // Sauces
return false;
}
}
}
}
return true;
}
Note 1: I know about the rule "If it works, don't touch it" but I feel like this code is getting in the territory of spaghetti code with a bunch of ifs essentially checking similar things with lots of cases and just wanted a second opinion if there is a more optimized way I can't think of right now.注意 1:我知道“如果它有效,请不要碰它”的规则,但我觉得这段代码正在进入意大利面条代码的领域,其中有一堆 ifs 基本上检查了很多情况下类似的事情,只是想要一个第二种意见,如果我现在想不出更优化的方式。
Note 2: I chose HashSet over ArrayList for the menu because it is faster to search.注意 2:我为菜单选择了 HashSet 而不是 ArrayList,因为它的搜索速度更快。
The problem I see with your proposed solution is that it is trying to solve all problems at once, instead of solving them separately.我在您提出的解决方案中看到的问题是它试图一次解决所有问题,而不是单独解决它们。 That makes your code hard to read and understand, in my opinion.
在我看来,这使您的代码难以阅读和理解。 While it may work, the more business rules you add, the harder this will get.
虽然它可能有效,但您添加的业务规则越多,这就越难。
So what can you do about it?所以你对此能做些什么? Separate the concerns.
分离关注点。
The first concern is cassifying an ingredient: is it bread, cheese, meat, extra, sauce?第一个问题是对一种成分进行分类:是面包、奶酪、肉、额外的还是酱汁? You could eg create a class
Menu
with a method getCategory()
(instead of just using a HashSet
for menu) that returns the category, and the return value could be an Enum.例如,您可以使用返回类别的方法
getCategory()
(而不仅仅是对Menu
使用HashSet
)创建一个菜单类,并且返回值可以是一个枚举。
The seond concern is order.第二个问题是秩序。 You could check the order of the list using a custom
Comparator
.您可以使用自定义
Comparator
检查列表的顺序。 See this question for details.有关详细信息,请参阅此问题。
The third concern is number of ingredients of a certain category.第三个关注点是某一类别的成分数量。 Given that you can find out the category of an ingredient, you can count how many you have and check if it is the right amount.
鉴于您可以找出一种成分的类别,您可以计算您有多少并检查它是否正确。
There are more things to be said about how to achieve any of this, I just wanted to point you in a possible direction.关于如何实现这一点还有很多话要说,我只是想为您指出一个可能的方向。
First, there is nothing really wrong with your general approach.首先,您的一般方法没有什么问题。
Having said that, there are some errors.话虽如此,还是有一些错误。
isValid()
from within a static context (Main) but the method is not declared static.isValid()
) 但该方法未声明为静态的。 This is how I might approach it.这就是我可能接近它的方式。 And it's not to say it is the best approach or style either.
这也不是说它是最好的方法或风格。
I chose to use an enum
to hold details about each menu item, and a class to process the order.我选择使用
enum
来保存每个菜单项的详细信息,并使用一个类来处理订单。 Enum's easily lend themselves to this type of requirement. Enum 很容易满足这种类型的要求。 I recommend you read up on them (they are too involved to explain them in detail here).
我建议您阅读它们(它们过于复杂,无法在此处详细解释)。 But because they are
static
they are best served in holding values that are not likely to change.但是因为它们是
static
的,所以它们最好用于持有不太可能改变的值。
Each item has two arguments are are processed in the enum's
constructor.每个项目都有两个参数,都在
enum's
构造函数中处理。
so each item has a separate range of its item (the ingredient)所以每个项目都有一个单独的项目范围(成分)
the enum
also has a validate method to check to see if a supplied count of items meets the requirements. enum
还有一个 validate 方法来检查提供的项目计数是否符合要求。
The actual order is in the MyOrder
class.实际订单在
MyOrder
类中。
enum Menu {MEAT(0,1), BREAD(1,1), CHEESE(1,1), EXTRAS(1,3), SAUCES(1,3);
private int min;
private int max;
private Menu(int min, int max) {
this.min = min;
this.max = max;
}
public int getMax() {
return max;
}
public int getMin() {
return min;
}
public boolean validate(int count) {
return count >= min && count <= max;
}
}
class MyOrder {
private EnumMap<Menu, Integer> counts = new EnumMap<>(Menu.class);
public void display() {
for (Menu item : Menu.values()) {
int count = counts.get(item);
System.out.printf("%-7s: %d (%d,%d) %s%n",item.name(), count, item.getMin(), item.getMax(),
item.validate(count) ? "" : "Item count out of range.");
}
}
public boolean add(Menu item, int quantity) {
return item.validate(counts.merge(item, quantity, Integer::sum));
}
}
public class Restaurant {
public static void main(String[] args) {
boolean isValid;
MyOrder order = new MyOrder();
isValid = order.add(Menu.BREAD,2);
isValid &= order.add(Menu.MEAT,1);
isValid &= order.add(Menu.CHEESE,2);
isValid &= order.add(Menu.EXTRAS,3);
isValid &= order.add(Menu.SAUCES,2);
if (isValid) {
System.out.println("Your order is accepted.");
} else {
System.out.println("Order is not in compliance");
order.display();
}
}
}
prints印刷
Order is not in compliance
MEAT : 1 (0,1)
BREAD : 1 (1,1)
CHEESE : 2 (1,1) Item count out of range.
EXTRAS : 3 (1,3)
SAUCES : 2 (1,3)
Also remember that the result of any if statement
is a boolean
.还要记住,任何
if statement
的结果都是boolean
。 So the inequality
can be assigned to a boolean and then tested later (if it makes sense to do so).因此,可以将
inequality
分配给布尔值,然后稍后进行测试(如果这样做有意义的话)。 Also notice that I don't check for a legitimate order until the end.另请注意,我直到最后才检查合法订单。 Some might prefer to signal a bad order as soon as it occurs.
有些人可能更愿意在订单出现错误时立即发出信号。 This is a design choice.
这是一种设计选择。
For more information check.欲了解更多信息检查。
Enum 枚举
EnumMap 枚举映射
Map.merge 地图合并
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.