如何在 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;
}
我制作了一个 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;
}