比较 Stream 中的元素
Comparing elements within Stream
假设我有一个项目列表,我使用 Stream 将它转换为另一种类型的列表。还假设原始 itemList
是从数据库中检索的,并按最后更新的时间戳排序,我想保留排序。 (这样就无法对 Stream 进行排序)。我想找出这些元素中的最高价格,如果是,则在 ItemResponse 中设置 isMax 指示器。如果我想使用相同的 Stream 执行此操作,该怎么做?
我想到的一种方法是创建另一个流来比较它,但是,这似乎是重复的工作(在相同的元素上循环两次)。
还是在这种情况下不使用 Stream 并将原始 Stream 转换回 for 循环更好?
List<Item> itemList = Arrays.asList(
new Item(BigDecimal.valueOf(10), 1),
new Item(BigDecimal.valueOf(20), 2));
List<ItemResponse> itemResponseList = itemList.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
//adding logic to find the max and set the max indicator, but how ?
return itemResponse;
})
.collect(Collectors.toList());
//attempt 1 - it works, but it loops the same elements again
Optional<ItemResponse> max = itemResponseList.stream()
.collect(Collectors.maxBy(Comparator.comparingDouble(itemResponse -> itemResponse.getPrice().doubleValue())));
max.ifPresent(e -> e.setMax(true));
public class Item {
private BigDecimal amount;
private int id;
Item(BigDecimal amount, int id) {
this.amount = amount;
this.id = id;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public class ItemResponse {
private BigDecimal price;
private Boolean isMax;
private int id;
ItemResponse() {};
public Boolean getMax() {
return isMax;
}
public void setMax(Boolean max) {
isMax = max;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "id: " + id + ", price: " + price + ", isMax: " + isMax;
}
}
您可以制作一个降序排序的列表并只更新列表的头部。
List<Item> itemList = Arrays.asList(
new Item(BigDecimal.valueOf(10), 1),
new Item(BigDecimal.valueOf(20), 2));
List<ItemResponse> itemResponseList = itemList.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
return itemResponse;
})
// reverse sorting
.sorted(Comaparator.comparing(ItemResponse::getPrice).reversed())
.collect(Collectors.toList());
// only first will be updated, if the list is non-empty
itemResponseList.stream().findFirst().ifPresent(e -> e.setMax(true));
假设在一般情况下多个项目可能有最高 and/or 最低价格,看来流方法无助于避免重复迭代。相反,应该使用循环将项目转换为项目响应,并构建两个具有最高/最低价格的中间项目列表,然后迭代较小的列表并设置适当的指标。
List<ItemResponse> itemResponseList = new ArrayList<>();
List<ItemResponse> maxPriced = new ArrayList<>();
List<ItemResponse> minPriced = new ArrayList<>();
BigDecimal minPrice = null;
BigDecimal maxPrice = null;
for (Item item : itemList) {
ItemResponse ir = new ItemResponse();
ir.setId(item.getId());
ir.setPrice(item.getAmount());
if (null == minPrice || minPrice.compareTo(ir.getPrice()) >= 0) {
if (null == minPrice || minPrice.compareTo(ir.getPrice()) > 0) {
minPrice = ir.getPrice();
minPriced.clear();
}
minPriced.add(ir);
}
if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) <= 0) {
if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) < 0) {
maxPrice = ir.getPrice();
maxPriced.clear();
}
maxPriced.add(ir);
}
itemResponseList.add(ir);
}
minPriced.forEach(i -> i.setMin(true));
maxPriced.forEach(i -> i.setMax(true));
或者,最好只准备 运行 数据库查询以获取 max/min 价格,然后使用这些值在 one 流中设置指标.
BigDecimal[] minMax = getMinMaxPrices(); // {min. max}
List<ItemResponse> itemResponseList = itemList
.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
itemResponse.setMin(item.getAmount().equals(minMax[0]));
itemResponse.setMax(item.getAmount().equals(minMax[1]));
return itemResponse;
})
.collect(Collectors.toList());
假设我有一个项目列表,我使用 Stream 将它转换为另一种类型的列表。还假设原始 itemList
是从数据库中检索的,并按最后更新的时间戳排序,我想保留排序。 (这样就无法对 Stream 进行排序)。我想找出这些元素中的最高价格,如果是,则在 ItemResponse 中设置 isMax 指示器。如果我想使用相同的 Stream 执行此操作,该怎么做?
我想到的一种方法是创建另一个流来比较它,但是,这似乎是重复的工作(在相同的元素上循环两次)。
还是在这种情况下不使用 Stream 并将原始 Stream 转换回 for 循环更好?
List<Item> itemList = Arrays.asList(
new Item(BigDecimal.valueOf(10), 1),
new Item(BigDecimal.valueOf(20), 2));
List<ItemResponse> itemResponseList = itemList.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
//adding logic to find the max and set the max indicator, but how ?
return itemResponse;
})
.collect(Collectors.toList());
//attempt 1 - it works, but it loops the same elements again
Optional<ItemResponse> max = itemResponseList.stream()
.collect(Collectors.maxBy(Comparator.comparingDouble(itemResponse -> itemResponse.getPrice().doubleValue())));
max.ifPresent(e -> e.setMax(true));
public class Item {
private BigDecimal amount;
private int id;
Item(BigDecimal amount, int id) {
this.amount = amount;
this.id = id;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public class ItemResponse {
private BigDecimal price;
private Boolean isMax;
private int id;
ItemResponse() {};
public Boolean getMax() {
return isMax;
}
public void setMax(Boolean max) {
isMax = max;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "id: " + id + ", price: " + price + ", isMax: " + isMax;
}
}
您可以制作一个降序排序的列表并只更新列表的头部。
List<Item> itemList = Arrays.asList(
new Item(BigDecimal.valueOf(10), 1),
new Item(BigDecimal.valueOf(20), 2));
List<ItemResponse> itemResponseList = itemList.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
return itemResponse;
})
// reverse sorting
.sorted(Comaparator.comparing(ItemResponse::getPrice).reversed())
.collect(Collectors.toList());
// only first will be updated, if the list is non-empty
itemResponseList.stream().findFirst().ifPresent(e -> e.setMax(true));
假设在一般情况下多个项目可能有最高 and/or 最低价格,看来流方法无助于避免重复迭代。相反,应该使用循环将项目转换为项目响应,并构建两个具有最高/最低价格的中间项目列表,然后迭代较小的列表并设置适当的指标。
List<ItemResponse> itemResponseList = new ArrayList<>();
List<ItemResponse> maxPriced = new ArrayList<>();
List<ItemResponse> minPriced = new ArrayList<>();
BigDecimal minPrice = null;
BigDecimal maxPrice = null;
for (Item item : itemList) {
ItemResponse ir = new ItemResponse();
ir.setId(item.getId());
ir.setPrice(item.getAmount());
if (null == minPrice || minPrice.compareTo(ir.getPrice()) >= 0) {
if (null == minPrice || minPrice.compareTo(ir.getPrice()) > 0) {
minPrice = ir.getPrice();
minPriced.clear();
}
minPriced.add(ir);
}
if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) <= 0) {
if (null == maxPrice || maxPrice.compareTo(ir.getPrice()) < 0) {
maxPrice = ir.getPrice();
maxPriced.clear();
}
maxPriced.add(ir);
}
itemResponseList.add(ir);
}
minPriced.forEach(i -> i.setMin(true));
maxPriced.forEach(i -> i.setMax(true));
或者,最好只准备 运行 数据库查询以获取 max/min 价格,然后使用这些值在 one 流中设置指标.
BigDecimal[] minMax = getMinMaxPrices(); // {min. max}
List<ItemResponse> itemResponseList = itemList
.stream()
.map(item -> {
ItemResponse itemResponse = new ItemResponse();
itemResponse.setId(item.getId());
itemResponse.setPrice(item.getAmount());
itemResponse.setMin(item.getAmount().equals(minMax[0]));
itemResponse.setMax(item.getAmount().equals(minMax[1]));
return itemResponse;
})
.collect(Collectors.toList());