如何在 ObservableList<> 中总结具有相同名称的对象

How to sum up Objects with same name within ObservableList<>

我制作了一个 TableView,其中填充了来自数据库的成分对象。我想检查是否有具有相同名称和单位的成分对象,如果有,则将它们的数量加起来为一个成分对象。

我尝试使用 2 个嵌套的 for 循环并检查检查条件。 举例来说,我的 ObservableList 中有 2 个相同的成分对象,我用下面的代码填充了我的 TableView,我得到了之前的成分加总和。

控制器的相关部分Class:

@FXML 
    void loadData(ActionEvent e) throws Exception{
//      System.out.println(menuList.size());
        ObservableList<ObservableList<Ingredients>> result = FXCollections.observableArrayList();
        ObservableList<Ingredients> all = FXCollections.observableArrayList();
        try {
            for(String s : menuList) {
                result.add(DBUtils.getIngredById(DBUtils.getContent(s)));
            }
            for(ObservableList<Ingredients> obs : result) {
                for(Ingredients i : obs) {
                    all.add(i);
                }
            }
            ObservableList<Ingredients> asdad = mergeList(all);
            loadTable(asdad);
        } catch (Exception ex) {
            System.out.println("Error in loadTable()\n");
            throw ex;
        }
    }

private ObservableList<Ingredients> mergeList(ObservableList<Ingredients> all) {
    ObservableList<Ingredients> newList = FXCollections.observableArrayList();
    for(Ingredients i : all) {
        for(Ingredients m : all) {
            if(all.indexOf(i) != all.indexOf(m)) {
                if(i.getIngred().equals(m.getIngred())) {
                    if(i.getUnit().equals(m.getUnit())) {
                        newList.add(sumUpIng(i, m));
                    }
                }
            }else {
                newList.add(m);
            }
        }

    }
    return newList;
}

private Ingredients sumUpIng(Ingredients i, Ingredients s) {
    Ingredients ing = new Ingredients();
    ing.setAmount(i.getAmount() + s.getAmount());
    ing.setUnit(i.getUnit());
    ing.setIngred(i.getIngred());

    return ing;
}

private void loadTable(ObservableList<Ingredients> data) {
    tblShopping.setItems(data);
}

成分Class https://pastebin.com/N35LeDf4

public class Ingredients {

    private IntegerProperty id;
    private DoubleProperty amount;
    private StringProperty unit;
    private StringProperty ingred;

    public Ingredients() {
        this.id = new SimpleIntegerProperty();
        this.amount = new SimpleDoubleProperty();
        this.unit = new SimpleStringProperty();
        this.ingred = new SimpleStringProperty();
    }
    //getters and setters
}

您的嵌套循环将无法正常工作。这样做的一个原因是它针对每个索引组合执行。对于不相等的索引,循环执行两次。此外,可能有超过 2 种成分具有相同的 unit/ingred 属性 组合。这样做的最好方法似乎是存储 Map 映射的索引,从 unit/ingred 键的组合到 Integer 包含包含索引的值的值结果列表中具有此组合的元素。

/**
 * Class implementing hashCode/equals based on ingred and unit
 * for use as key in a HashMap
 */
private static class IngredientWrapper {
    private final Ingredients ingredient;

    private IngredientWrapper(Ingredients ingredient) {
        this.ingredient = ingredient;
    }

    @Override
    public int hashCode() {
        return Objects.hash(ingredient.getIngred(), ingredient.getUnit());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        IngredientWrapper other = (IngredientWrapper) obj;
        return Objects.equals(ingredient.getIngred(), other.ingredient.getIngred())
                && Objects.equals(ingredient.getUnit(), other.ingredient.getUnit());
    }

}

private static ObservableList<Ingredients> mergeList(ObservableList<Ingredients> all) {
    ObservableList<Ingredients> newList = FXCollections.observableArrayList();
    Map<IngredientWrapper, Integer> indices = new HashMap<>();
    Integer index = 0;

    for(Ingredients ingredient : all) {
        Integer listIndex = indices.putIfAbsent(new IngredientWrapper(ingredient), index);
        if (listIndex == null) {
            // combination not yet in the list
            newList.add(ingredient);
            index++;
        } else {
            // combination already in the list
            Ingredients listIngredient = newList.get(listIndex);
            listIngredient.setAmount(listIngredient.getAmount() + ingredient.getAmount());
        }

    }
    return newList;
}