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

时间:2018-12-19 22:23:19

标签: java javafx observable add

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

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

控制器类的相关部分:

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

成分类 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
}

1 个答案:

答案 0 :(得分:0)

您的嵌套循环无法正常工作。原因之一是它对索引的每个组合都执行。对于不相等的索引,循环执行两次。此外,可能有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;
}