我想用多个变量分组,用数字求和,用java中的list得到结果。与SQL group by一样,我希望将数据记录与最低的字符串合并。我想做的与下面的SQL相同,
select orderId, itemId, itemName, itemGenre, sum(number) as number
from item
group by itemId, itemName, itemGenre;
如果数据存在于下面的项目表中,
orderId(PK), itemId, itemName, itemGenre, number
00-82-947, 8810, item name1, 01, 1
00-82-952, 8810, item name1, 01, 2
00-91-135, 8315, item name2, 02, 3
00-91-140, 8315, item name3, 02, 4
我预计结果会在下面。当用orderId按00-82-947和00-82-952分组时,我想像SQL分组一样得到较低的一个。
00-82-947, 8810, item name1, 01, 3,
00-91-135, 8315, item name2, 02, 3,
00-91-140, 8315, item name3, 02, 4
如何在Java中实现这一点?我认为这对我来说是可行的,但在这种情况下,未按分组的orderId将为null,因此我需要创建一个新类来填充orderId。http://codestudyblog.com/questions/sf/0421195604.html
这也可以,但是我想要列表的结果。所以我需要隐藏它来映射三次,因为我需要按三次分组。在java 8中按多个字段名称分组
所以我正在寻找一个更好的方法,可能使用java流。作为参考,我留下代码。
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Item {
private String orderId;
private String itemId;
private String itemName;
private String itemGenre;
private Integer number;
}
准备数据
final ArrayList<Item> items = new ArrayList<>();
items.add(new Item("00-82-947", "8810", "item name1", "01", 1));
items.add(new Item("00-82-952", "8810", "item name1", "01", 2));
items.add(new Item("00-91-135", "8315", "item name2", "02", 3));
items.add(new Item("00-91-140", "8315", "item name3", "02", 4));
System.out.println(items);
我希望打印结果如下。
[Item(orderId=00-82-947, itemId=8810, itemName=item name1, itemGenre=01, number=3),
Item(orderId=00-91-135, itemId=8315, itemName=item name2, itemGenre=02, number=3),
Item(orderId=00-91-140, itemId=8315, itemName=item name3, itemGenre=02, number=4)]
我喜欢让我的流代码保持简短,易于查看,即使有时这意味着需要在幕后隐藏更多代码才能正常工作。所以我的目标是:
List<Item> items = List.of(
new Item("00-82-947", "8810", "item name1", "01", 1),
new Item("00-82-952", "8810", "item name1", "01", 2),
new Item("00-91-135", "8315", "item name2", "02", 3),
new Item("00-91-140", "8315", "item name3", "02", 4));
Map<GroupByKey, List<Item>> lists = items.stream()
.collect(Collectors.groupingBy(Item::getGroupByKey));
Map<GroupByKey, SumForOrder> grouped = lists.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> new SumForOrder(e.getValue())));
grouped.forEach((k, v) -> System.out.println("" + k + " -> " + v));
输出:
8810 item name1 01 -> 00-82-947 3
8315 item name3 02 -> 00-91-140 4
8315 item name2 02 -> 00-91-135 3
我首先执行一个常规的groupingBy
操作,将您的项目排序到每个组的列表中。为此,我创建了一个GroupByKey
类,其中包含itemId
、itemName
和itemgree
,以及一个Item
类的getGroupByKey
方法,用于构造GroupByKey
对象。
public GroupByKey getGroupByKey() {
return new GroupByKey(itemId, itemName, itemGenre);
}
接下来,我将列表映射转换为一个映射,其中包含我为此创建的另一个类的对象,SumForOrder
。SumForOrder
的构造器完成了大量实际工作,从一系列项目中找到最小的orderId
,并对数字进行汇总:
public class SumForOrder {
private String orderId;
private int sum;
public SumForOrder(Collection<Item> itemsForOrder) {
orderId = itemsForOrder.stream()
.map(Item::getOrderId)
.min(Comparator.naturalOrder())
.orElseThrow();
sum = itemsForOrder.stream()
.map(Item::getNumber)
.filter(Objects::nonNull)
.mapToInt(Integer::intValue)
.sum();
}
@Override
public String toString() {
return String.format("%-9s %2d", orderId, sum);
}
}
您也可以简单地创建新的Item
对象,而不是SumFororder
对象。在这种情况下,您不需要SumFororder
类。
SQL查询似乎缺少应用于orderId
的聚合函数MIN
:
sql prettyprint-override">SELECT MIN(orderId), itemId, itemName, itemGenre, SUM(number) as number
FROM item
GROUP BY itemId, itemName, itemGenre;
要使用Stream APICollectors.toMap
实现类似的功能,应该使用合并函数,合并函数选择一分钟的orderId
并求和号
。使用LinkedHashMap来保持插入顺序可能更好。
此外,在选择要放置到中间映射的值时,应该在项
类中实现复制构造函数,或者从项
列表中克隆项。
然后将此映射的值转换为ArrayList
。
List<Item> summary = new ArrayList<>(items
.stream()
.collect(Collectors.toMap(
// compound "group by" key using fields for brevity
i -> String.join("|", i.itemId, i.itemName, i.itemGenre),
i -> i.clone(), // or Item::new if copy constructor is implemented
// or verbose i -> new Item(i.orderId, i.itemId, ...)
(i1, i2) -> {
if (i1.orderId.compareToIgnoreCase(i2.orderId) < 0) {
i1.setOrderId(i2.orderId);
}
i1.setNumber(i1.number + i2.number);
return i1;
},
LinkedHashMap::new
),
)
.values() // Collection<Item>
);
或者,可以在合并函数中创建一个新对象:
List<Item> summary = new ArrayList<>(items
.stream()
.collect(Collectors.toMap(
// compound "group by" key using fields for brevity
i -> String.join("|", i.itemId, i.itemName, i.itemGenre),
i -> i, // or Function.identity()
(i1, i2) -> new Item( // merge function
i1.orderId.compareToIgnoreCase(i2.orderId) <= 0 ? i1.orderId : i2.orderId,
i1.itemId, i1.itemName, i1.itemGenre, // "group by" fields
i1.number + i2.number
),
LinkedHashMap::new
))
.values() // Collection<Item>
);
您需要将min()
聚合函数应用于orderid
,如下所示:
select min(orderId), itemId, itemName, itemGenre, sum(number) as number
from item
group by itemId, itemName, itemGenre;
试试这个。
static String min(String a, String b) { return a.compareTo(b) <= 0 ? a : b; }
public static void main(String[] args) {
record Item(String orderId, String itemId, String itemName, String itemGenre, Integer number) {}
List<Item> items = List.of(
new Item("00-82-947", "8810", "item name1", "01", 1),
new Item("00-82-952", "8810", "item name1", "01", 2),
new Item("00-91-135", "8315", "item name2", "02", 3),
new Item("00-91-140", "8315", "item name3", "02", 4));
record ItemKey(String itemId, String itemName, String itemGenre) {}
record ItemValue(String orderId, Integer number) {}
Map<ItemKey, ItemValue> map = items.stream()
.collect(Collectors.toMap(
e -> new ItemKey(e.itemId(), e.itemName(), e.itemGenre()),
e -> new ItemValue(e.orderId(), e.number()),
(a, b) -> new ItemValue(min(a.orderId(), b.orderId()), a.number() + b.number()),
LinkedHashMap::new));
for (Entry<ItemKey, ItemValue> e : map.entrySet())
System.out.println(e);
}
输出:
ItemKey[itemId=8810, itemName=item name1, itemGenre=01]=ItemValue[orderId=00-82-947, number=3]
ItemKey[itemId=8315, itemName=item name2, itemGenre=02]=ItemValue[orderId=00-91-135, number=3]
ItemKey[itemId=8315, itemName=item name3, itemGenre=02]=ItemValue[orderId=00-91-140, number=4]
问题内容: 对于我的示例,拥有汽车对象,并根据模型(分组依据)发现了最小和最大价格值。 但是我找不到哪个汽车对象具有最高和最低价格。我怎样才能做到这一点? 问题答案: 如果您只对每个组感兴趣,则可以使用,例如 但是,由于您想要最昂贵和最便宜的产品,因此需要以下内容: 由于没有与之等效的通用统计对象,因此该解决方案带来了一些不便。如果这种情况不止一次发生,那么值得用这样的类填补空白: 将其添加到您的
我怎样才能以最有效的方式做到这一点? 用于测试的主类示例
我有以下文件: 如何发出请求,将Sigle\U 1和Sigle\U 2连接起来,并将值reslut分组? 预期结果示例: 我试过了,但还不完全
以我的例子为例,有一个car对象,并发现基于模型(group by)的最小和最大价格值。 但我找不到哪些汽车物品有最大和最小的价格。我怎么能那样做?
我可以同时使用和吗?
我有一个带有分组变量的数据帧,我想按组对它们求和。使用很容易。 但是现在我想要一个新的列,按组计算n1和n2的总和。这样地: 我如何使用dplyr? 编辑:实际上,这只是一个例子,我有很多变量。 我试过这两个代码,但它不在正确的维度上......