[英]Is there a Java equivalent of C#'s LINQ "Select" function
LINQ has Enuemerable.Select , does Java have any equivalent? LINQ 有Enuemerable.Select ,Java 有什么等价物吗?
Say I have some class Record with three fields id , price , itemsSold and a list of these records from which I want to filter out the most popular item measured by which product sold the most items.假设我有一些 class记录,其中包含三个字段id 、 price 、 itemsSold和这些记录的列表,我想从中筛选出最受欢迎的商品,这些商品是根据哪种产品销售最多的商品来衡量的。
In LINQ I could do something like this在 LINQ 我可以做这样的事情
var mostPopularItem = records.GroupBy(sr => sr.Id)
.Select(g => new
{
Id = g.Key,
TotalSold = g.Sum(r => r.ItemsSold)
})
.OrderByDescending(i => i.TotalSold).First();
by using the Select(...)
method to reconstruct into a suitable form.通过使用
Select(...)
方法重构为合适的形式。 How would I do the same in Java?我如何在 Java 中做同样的事情? I could simply use streams to extract the actual number
我可以简单地使用流来提取实际数字
records.stream().map(r -> r.getItemsSold()).sorted(Comparator.reverseOrder()).collect(Collectors.toList)).get(0)
but this would only give me an array of the items sold sorted in descending order.但这只会给我一组按降序排列的已售商品。 Optimally I would like to end up with an object that contains the id and the itemsSold .
最理想的是,我希望最终得到一个包含id和 itemsSold 的object 。
The equivalent of Select
in Java is the map
-function on Stream
. Select
中的 Select 相当于Stream
上的map
函数。 But in your case, you probably want to use the second parameter of groupingBy
-collector to sum up the ItemsSold
-values.但在您的情况下,您可能希望使用
groupingBy
-collector 的第二个参数来总结ItemsSold
- 值。
Java doesn't have is anonymous objects, like you create in your Select
-call. Java 没有匿名对象,就像您在
Select
调用中创建的那样。 So you would need to define a class or record to hold that data.因此,您需要定义一个 class 或记录来保存该数据。
Using records, you could do this:使用记录,您可以这样做:
record TotalSoldRecord(String id, int totalSold) {}
var mostPopularItem = records.stream()
// Grouping by ID into a Map<String, int>, where the keys are
// the recordIds and the values are the sum of "itemsSold".
.collect(Collectors.groupingBy(Record::getId,
Collectors.summingInt(Record::getItemsSold)))
.entrySet()
.stream()
.map(entry -> new TotalSoldRecord(entry.getKey(), entry.getValue()))
// Finding the TotalSoldRecord with the maximum totalSold.
.max(Comparator.comparingInt(TotalSoldRecord::totalSold));
Note: You could also use Map.Entry
as the result instead of mapping it to TotalSoldRecord
.注意:您也可以使用
Map.Entry
作为结果,而不是将其映射到TotalSoldRecord
。
This should return the most popular item:这应该返回最受欢迎的项目:
var itemsSoldById = records.stream()
.collect(groupingBy(rec -> rec.getId(), summingInt(rec -> rec.getItemsSold())));
var mostPopularItem = itemsSoldById
.entrySet()
.stream()
.max(Comparator.comparingInt(Map.Entry::getValue))
.orElseThrow(()-> new IllegalStateException("The list of records is empty"));
Previous version before my edit that did not group records by id:我编辑之前的上一个版本没有按 id 对记录进行分组:
var mostPopularItem = records.stream()
.sorted(Comparator.comparing(rec -> rec.getItemsSold()))
.reduce((rec1 , rec2) -> rec1.getItemsSold() > rec2.getItemsSold() ? rec1 : rec2)
.orElseThrow(()-> new IllegalStateException("The list of records is empty"));
Something like this?是这样的吗?
package example.stackoverflow;
import java.util.List;
import java.util.stream.Collectors;
public class Select {
public static void main(String[] args) {
record Thing(String id, int price, int itemsSold){}
List<Thing> records = List.of(
new Thing("a", 5, 14),
new Thing("b", 4, 33),
new Thing("c", 6, 10),
new Thing("a", 5, 21),
new Thing("c", 6, 12)
);
record PopularThing(String id, int totalSold){}
records.stream()
.collect(Collectors.groupingBy(Thing::id, Collectors.summingInt(Thing::itemsSold)))
.entrySet().stream().map(e -> new PopularThing(e.getKey(), e.getValue()))
.max((a,b) -> a.totalSold - b.totalSold)
.ifPresent(System.out::println);
}
}
List<Record> recordList = new ArrayList<>();
recordList.add(new Record(1L, new BigDecimal(2), 4));
recordList.add(new Record(1L, new BigDecimal(2), 5));
recordList.add(new Record(1L, new BigDecimal(2), 7));
recordList.add(new Record(2L, new BigDecimal(2), 10));
Map.Entry<Long, Integer> mostPopularItem = recordList.stream().collect(groupingBy(Record::getId, summingInt(Record::getItemsSold))).entrySet().stream().max(Map.Entry.comparingByValue()).orElse(null);
Output: Output:
Key = 1, Value = 16
public class Record {
public Record(Long id, BigDecimal price, Integer itemsSold) {
this.id = id;
this.price = price;
this.itemsSold = itemsSold;
}
private Long id;
private BigDecimal price;
private Integer itemsSold;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getItemsSold() {
return itemsSold;
}
public void setItemsSold(Integer itemsSold) {
this.itemsSold = itemsSold;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.