如何对列表中具有相同 ID 的每组元素应用算术运算
How to apply an Arithmetic operation on each Group of elements with the same ID in the list
我有 class Data10
有 4 个字段。
我有一个 Data10
个对象的列表。
我想对具有 相同 的元素的 值 进行 算术运算 ID。作为最终结果,我需要生成具有相同 ID、相同 year
、新 name
("D"
) 的新 Data10
对象,和value
(基于算术运算)。
public class Data10 {
int id;
int year;
String name;
BigDecimal value;
}
List<Data10> list = new ArrayList();
list.add(new Data10(1, 2020, "A", new BigDecimal(5.5)));
list.add(new Data10(1, 2020, "B", new BigDecimal(2.5)));
list.add(new Data10(1, 2020, "C", new BigDecimal(8.5)));
list.add(new Data10(2, 2020, "A", new BigDecimal(1.5)));
list.add(new Data10(2, 2020, "B", new BigDecimal(6.5)));
list.add(new Data10(2, 2020, "C", new BigDecimal(2.5)));
list.add(new Data10(3, 2020, "A", new BigDecimal(6.5)));
list.add(new Data10(3, 2020, "B", new BigDecimal(1.5)));
list.add(new Data10(3, 2020, "C", new BigDecimal(9.5)));
list.add(new Data10(4, 2020, "A", new BigDecimal(3.5)));
list.add(new Data10(4, 2020, "B", new BigDecimal(7.5)));
list.add(new Data10(4, 2020, "C", new BigDecimal(5.5)));
我想对每组 ID 应用下面的 公式:
D = A - (B * C) [Airthmetic operation for group of objects with the same ID]
我对对象名称 ("A|B|C"
) 应用了过滤器,以便只有具有这些名称的元素才能出现在列表中。并且每个名称和 Id 将只有一个唯一对象。
我试过根据 ID 对列表进行分组,但不知道如何在每个组中应用该公式。
list.stream().filter(data10 -> data10.getName().matches("A|B|C"))
.collect(Collectors.groupingBy(Data10::getId));
预期:
Data10(1, 2020, "D", -15.75); [ Formula (D= 5.5 - (2.5 * 8.5)) ]
Data10(2, 2020, "D", -14.75); [ Formula (D= 1.5 - (6.5 * 2.5)) ]
Data10(3, 2020, "D", -7.75); [ Formula (D= 6.5 - (1.5 * 9.5)) ]
Data10(4, 2020, "D", -37.75); [ Formula (D= 3.5 - (7.5 * 5.5)) ]
按id对列表进行分组,然后循环遍历每个组并获取a、b和c值,
将新数据添加到具有 D 名称和公式值的列表中。
list.stream()
.collect(Collectors.groupingBy(Data10::getId))
.entrySet().forEach(e -> {
var a = e.getValue().stream().filter(d -> d.getName().equals("A")).findFirst().get().getValue();
var b = e.getValue().stream().filter(d -> d.getName().equals("B")).findFirst().get().getValue();
var c = e.getValue().stream().filter(d -> d.getName().equals("C")).findFirst().get().getValue();
var formula = new BigDecimal(a.subtract(b.multiply(c)).doubleValue());
list.add(new Data10(e.getKey(), 2020, "D", formula));
});
您可以先通过 id
对这些对象进行分组,然后通过 name
和 Collectors.groupingBy
进行分组,这将生成嵌套地图。然后通过为地图中的每个值生成一个新的 data-object 将这个中间地图缩减为列表。
public static void main(String[] args) {
List<Data10> data10List = // initializing the list
List<Data10> result =
data10List.stream()
.collect(Collectors.groupingBy(Data10::getId, // by id
Collectors.groupingBy(Data10::getName))) // by name
.values().stream()
.map(map -> processValues(map))
.collect(Collectors.toList());
result.forEach(System.out::println); // printing the result
}
对于下面的方法,我假设所有组合 id
和 name
是独一无二的。因此,地图中的每个列表将只包含一个元素(注意:hard-coded names 以及 hard-coded math logic, 通常要避免).
public static Data10 processValues(Map<String, List<Data10>> map) {
BigDecimal combinedValue =
map.get("A").get(0).getValue() // "A"
.subtract(map.get("B").get(0).getValue() // "B"
.multiply(map.get("C").get(0).getValue())); // "C"
return new Data10(map.get("A").get(0).getId(),
map.get("A").get(0).getYear(),
"D",
combinedValue);
}
为了避免hard-coding数学运算的逻辑,你可以定义一个自定义的函数式接口([=57中没有build-in函数=] 需要三个参数)。并通过将此接口和预期名称作为参数添加到声明中,使方法 processValues()
更加通用。这样就可以应用不同的数学逻辑而无需更改方法。
接口和实现可能如下所示:
@FunctionalInterface
interface TripleFunction<A, B, C, R> {
R calculate(A a, B b, C c);
}
TripleFunction<BigDecimal, BigDecimal, BigDecimal, BigDecimal> mathOperation =
(a, b, c) -> a.subtract(b.multiply(c));
这些是使用此函数所需的更改(在流管道和 processValues
内部):
.map(map -> processValues(map, mathOperation, "A", "B", "C"))
public static Data10 processValues(Map<String, List<Data10>> map,
TripleFunction<BigDecimal, BigDecimal, BigDecimal, BigDecimal> mathOperation,
String a, String b, String c) {
BigDecimal combinedValue = mathOperation
.calculate(map.get(a).get(0).getValue(),
map.get(b).get(0).getValue(),
map.get(c).get(0).getValue());
return new Data10(map.get("A").get(0).getId(),
map.get("A").get(0).getYear(),
"D",
combinedValue);
}
输出(问题中列出的数据,用作输入)
Data10{id=1, year=2020, name='D', value=-15.75}
Data10{id=2, year=2020, name='D', value=-14.75}
Data10{id=3, year=2020, name='D', value=-7.75}
Data10{id=4, year=2020, name='D', value=-37.75}
我有 class Data10
有 4 个字段。
我有一个 Data10
个对象的列表。
我想对具有 相同 的元素的 值 进行 算术运算 ID。作为最终结果,我需要生成具有相同 ID、相同 year
、新 name
("D"
) 的新 Data10
对象,和value
(基于算术运算)。
public class Data10 {
int id;
int year;
String name;
BigDecimal value;
}
List<Data10> list = new ArrayList();
list.add(new Data10(1, 2020, "A", new BigDecimal(5.5)));
list.add(new Data10(1, 2020, "B", new BigDecimal(2.5)));
list.add(new Data10(1, 2020, "C", new BigDecimal(8.5)));
list.add(new Data10(2, 2020, "A", new BigDecimal(1.5)));
list.add(new Data10(2, 2020, "B", new BigDecimal(6.5)));
list.add(new Data10(2, 2020, "C", new BigDecimal(2.5)));
list.add(new Data10(3, 2020, "A", new BigDecimal(6.5)));
list.add(new Data10(3, 2020, "B", new BigDecimal(1.5)));
list.add(new Data10(3, 2020, "C", new BigDecimal(9.5)));
list.add(new Data10(4, 2020, "A", new BigDecimal(3.5)));
list.add(new Data10(4, 2020, "B", new BigDecimal(7.5)));
list.add(new Data10(4, 2020, "C", new BigDecimal(5.5)));
我想对每组 ID 应用下面的 公式:
D = A - (B * C) [Airthmetic operation for group of objects with the same ID]
我对对象名称 ("A|B|C"
) 应用了过滤器,以便只有具有这些名称的元素才能出现在列表中。并且每个名称和 Id 将只有一个唯一对象。
我试过根据 ID 对列表进行分组,但不知道如何在每个组中应用该公式。
list.stream().filter(data10 -> data10.getName().matches("A|B|C"))
.collect(Collectors.groupingBy(Data10::getId));
预期:
Data10(1, 2020, "D", -15.75); [ Formula (D= 5.5 - (2.5 * 8.5)) ]
Data10(2, 2020, "D", -14.75); [ Formula (D= 1.5 - (6.5 * 2.5)) ]
Data10(3, 2020, "D", -7.75); [ Formula (D= 6.5 - (1.5 * 9.5)) ]
Data10(4, 2020, "D", -37.75); [ Formula (D= 3.5 - (7.5 * 5.5)) ]
按id对列表进行分组,然后循环遍历每个组并获取a、b和c值, 将新数据添加到具有 D 名称和公式值的列表中。
list.stream()
.collect(Collectors.groupingBy(Data10::getId))
.entrySet().forEach(e -> {
var a = e.getValue().stream().filter(d -> d.getName().equals("A")).findFirst().get().getValue();
var b = e.getValue().stream().filter(d -> d.getName().equals("B")).findFirst().get().getValue();
var c = e.getValue().stream().filter(d -> d.getName().equals("C")).findFirst().get().getValue();
var formula = new BigDecimal(a.subtract(b.multiply(c)).doubleValue());
list.add(new Data10(e.getKey(), 2020, "D", formula));
});
您可以先通过 id
对这些对象进行分组,然后通过 name
和 Collectors.groupingBy
进行分组,这将生成嵌套地图。然后通过为地图中的每个值生成一个新的 data-object 将这个中间地图缩减为列表。
public static void main(String[] args) {
List<Data10> data10List = // initializing the list
List<Data10> result =
data10List.stream()
.collect(Collectors.groupingBy(Data10::getId, // by id
Collectors.groupingBy(Data10::getName))) // by name
.values().stream()
.map(map -> processValues(map))
.collect(Collectors.toList());
result.forEach(System.out::println); // printing the result
}
对于下面的方法,我假设所有组合 id
和 name
是独一无二的。因此,地图中的每个列表将只包含一个元素(注意:hard-coded names 以及 hard-coded math logic, 通常要避免).
public static Data10 processValues(Map<String, List<Data10>> map) {
BigDecimal combinedValue =
map.get("A").get(0).getValue() // "A"
.subtract(map.get("B").get(0).getValue() // "B"
.multiply(map.get("C").get(0).getValue())); // "C"
return new Data10(map.get("A").get(0).getId(),
map.get("A").get(0).getYear(),
"D",
combinedValue);
}
为了避免hard-coding数学运算的逻辑,你可以定义一个自定义的函数式接口([=57中没有build-in函数=] 需要三个参数)。并通过将此接口和预期名称作为参数添加到声明中,使方法 processValues()
更加通用。这样就可以应用不同的数学逻辑而无需更改方法。
接口和实现可能如下所示:
@FunctionalInterface
interface TripleFunction<A, B, C, R> {
R calculate(A a, B b, C c);
}
TripleFunction<BigDecimal, BigDecimal, BigDecimal, BigDecimal> mathOperation =
(a, b, c) -> a.subtract(b.multiply(c));
这些是使用此函数所需的更改(在流管道和 processValues
内部):
.map(map -> processValues(map, mathOperation, "A", "B", "C"))
public static Data10 processValues(Map<String, List<Data10>> map,
TripleFunction<BigDecimal, BigDecimal, BigDecimal, BigDecimal> mathOperation,
String a, String b, String c) {
BigDecimal combinedValue = mathOperation
.calculate(map.get(a).get(0).getValue(),
map.get(b).get(0).getValue(),
map.get(c).get(0).getValue());
return new Data10(map.get("A").get(0).getId(),
map.get("A").get(0).getYear(),
"D",
combinedValue);
}
输出(问题中列出的数据,用作输入)
Data10{id=1, year=2020, name='D', value=-15.75}
Data10{id=2, year=2020, name='D', value=-14.75}
Data10{id=3, year=2020, name='D', value=-7.75}
Data10{id=4, year=2020, name='D', value=-37.75}