我制作了一个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
}
答案 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;
}