检查列表中的元素是否有效并且按正确的顺序为

发布于 2025-02-08 15:46:42 字数 2087 浏览 2 评论 0 原文

我正在制作一家地铁餐厅的复制品,您将在其中收到一定序列的订单,并检查序列是否有效,以及成分是否在菜单中。

正确的顺序是:1面包,0至1肉,1奶酪,1至3个额外的额外,1至3个调味料。

这意味着订单至少可以具有4种成分(面包,奶酪,另外1个调味料)和最多9种成分(面包,肉,奶酪,3种额外的额外,3个调味料)。

我的问题是,是否有更优化/更智能的方法可以验证比我的每种成分?

代码:

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

注意1:我知道规则“如果起作用,请不要触摸它“但是我觉得这个代码正在进入意大利面代码的领域,其中一堆IF基本上是在大量情况下检查类似的东西,而如果有一种更优化的方式,我现在想不到第二个意见。

注2:我选择菜单上的arraylist上的标签,因为搜索速度更快。

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.

The right order is: 1 bread, 0 to 1 meat, 1 cheese, 1 to 3 extras, 1 to 3 sauces.

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).

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.

Note 2: I chose HashSet over ArrayList for the menu because it is faster to search.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

楠木可依 2025-02-15 15:46:42

首先,您的一般方法没有真正的错。

话虽如此,有一些错误。

  • 您将hashmap视为通过餐厅的静态价值,该餐厅并未宣布为静态。
  • 您正在从静态上下文(main)中调用 iSvalid(),但该方法并未声明为静态。

这就是我可以处理的方式。这并不是说这是最好的方法或样式。

  • 我选择使用 enum 保留有关每个菜单项的详细信息,以及一个处理订单的类。 Enum很容易地满足这种要求。我建议您阅读它们(他们参与其中,无法在此处详细解释)。但是,由于它们是静态,最好在不可能更改的值中使用。

  • 每个项目都有两个参数在 enum的构造函数中进行处理。

  • 因此,每个项目都有其项目的单独范围(成分)

  • enum 还具有验证方法,可以检查提供的项目计数是否满足要求。

实际订单在 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();
        }
    }
}

打印

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) 

还请记住,如果语句是 boolean ,则任何的结果。因此,不等式可以分配给布尔值,然后进行稍后测试(如果这样做是有意义的)。另请注意,直到最后我才检查合法订单。有些人可能宁愿在发生不良订单时发出信号。这是一个设计选择。

有关更多信息检查。
enum

Map.merge

First, there is nothing really wrong with your general approach.

Having said that, there are some errors.

  • You are referencing your hashMap as a static value via Restaurant where it isn't declared static.
  • you are calling isValid() from within a static context (Main) but the method is not declared static.

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's easily lend themselves to this type of requirement. 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.

  • Each item has two arguments are are processed in the enum's constructor.

  • 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.

The actual order is in the MyOrder class.

  • it contains a map to hold the counts of each ingredient.
  • an add method to add the current quantity to the map for a given ingredient.
  • and a display method to print informative information about the order.
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. So the inequality can be assigned to a boolean and then tested later (if it makes sense to do so). 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

孤独岁月 2025-02-15 15:46:42

我在您提出的解决方案中看到的问题是,它试图一次解决所有问题,而不是单独解决它们。在我看来,这使您的代码难以阅读和理解。虽然可以正常工作,但您添加的业务规则就越多,它就会越难。

那你该怎么办?分开关注点。

第一个问题是要加入一种成分:是面包,奶酪,肉,额外的酱汁吗?您可以使用方法 getCategory()来创建类菜单(而不是仅使用返回类别的 HashSet ),并且回报值可能是枚举。

SEOND担忧是秩序。您可以使用自定义<代码>比较器检查列表的顺序。请参阅此问题有关详细信息。

第三个问题是特定类别的成分数量。鉴于您可以找出成分的类别,因此您可以计算有多少含量,并检查是否合适。

关于如何实现这一目标还有更多的话要说,我只想将您指向可能的方向。

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 e.g. 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.

The seond concern is order. You could check the order of the list using a custom 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文