[英]How to combine unlike streams in Java 8
我有一個Set<DateCount>
,它是使用以下代碼創建的。 這將創建一組7個DateCount
對象,其初始計數為0,從當前日期開始,代表當前星期的每一天。
// Create an initial Set of DateCount objects for the current week with counts of 0
Set<DateCount> dateCounts = IntStream.range(0, DAYS_IN_WEEK)
.mapToObj(idx -> new DateTime().withTimeAtStartOfDay().plusDays(idx))
.map(dt -> new DateCount(dt.toDate(), 0L))
.collect(toSet());
我有一個List<Object[]>
從數據庫存儲庫返回。 每個Object[]
在列表中有BigDecimal
索引0和一個Long
的索引1 BigDecimal
實際上是一個日期,像20141001
。 我想知道的是,是否有一種方法可以以Stream方式使用此數據更新dateCounts
集。 現在,我正在執行以下操作,僅遍歷對象數組列表並創建新的DateCount
對象,然后將其添加到dateCounts
集中。 DateCount
類具有自定義的equals()
和hashCode()
方法,以確保dateCounts
集合對於任何給定日期僅包含單個DateCount
實例。
data.stream()
.forEach(obj -> {
DateTime date = null;
try {
date = (sdf == null) ? new DateTime(obj[0]) : new DateTime(sdf.parse(obj[0].toString()));
dateCounts.add(new DateCount(date.toDate(), (Long) obj[1]));
} catch (ParseException e) {
e.printStackTrace();
}
});
在一個側面說明,我想知道如果有也避免做在我的lambda表達式一個try / catch只是解析的方式String
的Date
。
更新 -這是我到目前為止提出的。 雖然在.map調用中流過List<Object[]>
似乎並不自然,不確定是否有更好的方法。 我引入了自己的Tuple<X, Y>
類,因為在沒有訪問器方法的情況下,在流中使用Object[]
不能很好地工作。 同樣在最后兩行中,我正在創建一個帶有Comparator
的TreeSet
,以便可以按日期對數據進行排序。 我不認為這是最好的方法,但是我嘗試調用sorted()
並使DateCount
實現Comparable
看起來不錯,但是一旦調用collect(toSet())
方法,排序就會消失。 我認為這就是流式通話的本質。 我很好奇是否有一種方法可以在collect方法調用之前對其進行排序,並在調用collect之后保留排序。
Set<DateCount> dateCounts = IntStream.range(0, DAYS_IN_WEEK)
.mapToObj(idx -> new Tuple<>(new DateTime().withTimeAtStartOfDay().plusDays(idx).toDate(), 0L))
.map(t -> {
Tuple<String, Long> d = data.stream()
.map(arr -> new Tuple<>(arr[0].toString(), (Long) arr[1]))
.filter(tuple -> sdf.format(t.getX()).equals(tuple.getX()))
.findFirst().orElse(new Tuple<>(sdf.format(t.getX()), 0L));
return new DateCount(DateTime.parse(d.getX(), DateTimeFormat.forPattern("yyyyMMdd")).toDate(), d.getY());
})
.collect(toSet());
TreeSet<DateCount> set = new TreeSet<>((a, b) -> a.compareTo(b));
set.addAll(dateCounts);
您可以為集合提供Supplier
。 只需更換
.collect(toSet());
同
.collect(toCollection(() -> new TreeSet<>((a, b) -> a.compareTo(b))));
但是請注意,為Comparator
指定(a, b) -> a.compareTo(b)
意味着自然排序 。 如果您的元素實現Comparable
,則不必提供這樣的比較器。 您可以簡單地使用
.collect(toCollection(TreeSet::new));
如果DateCount
具有compareTo
方法但未實現Comparator
還可以指定DateCount::compareTo
而不是(a, b) -> a.compareTo(b)
。
請注意,在第一個mapToObj
操作中,沒有必要將DateTime
包裝在Tuple
。 您可以簡單地映射到DateTime
並在下一個map
操作中使用該值(因為我在那里僅看到t.getX()
,所以根本不使用第二個值為0L
值)。
畢竟,我不確定您要達到的目標,但我有強烈的感覺,您可以看看Collectors.groupingBy
…
您可以將數據庫數據映射到Map<DateTime,Long>
進行快速查找,因此您只需處理一次即可。 然后,當您遍歷Set<DateCount>
,可以使用peek()
更新的值。 這是一個例子。 我使用Date
代替DateTime
只是為了DateTime
示例代碼。
Instant baseDate = Instant.now();
Date date1 = new Date(baseDate.plus(1, ChronoUnit.DAYS).toEpochMilli());
Date date2 = new Date(baseDate.plus(2, ChronoUnit.DAYS).toEpochMilli());
Date date3 = new Date(baseDate.plus(3, ChronoUnit.DAYS).toEpochMilli());
Set<DateCount> dateCounts = new TreeSet<DateCount>(); // Our mock Set
dateCounts.add(new DateCount(date1, 0L));
dateCounts.add(new DateCount(date2, 0L));
dateCounts.add(new DateCount(date3, 0L));
List<Object[]> data = new ArrayList<Object[]>(); // Our mock database Data
data.add(new Object[]{date1.toInstant().toEpochMilli(), 5L});
data.add(new Object[]{date2.toInstant().toEpochMilli(), 3L});
data.add(new Object[]{date3.toInstant().toEpochMilli(), 2L});
//Map our data so we only have to process it once, and then we can look it up
Map<Date,Long> mappedData = data.stream()
.collect(Collectors.toConcurrentMap(k->new Date((long) k[0]), v->(Long)v[1]));
//Update the data using peek as we stream through it
dateCounts.stream()
.peek(dc->dc.setCount(mappedData.get(dc.getDate())))
.forEachOrdered(System.out::println);
運行時,這是輸出,以便您可以看到dateCounts已更新:
DateCount: Thu Dec 25 11:25:56 EST 2014 - 5
DateCount: Fri Dec 26 11:25:56 EST 2014 - 3
DateCount: Sat Dec 27 11:25:56 EST 2014 - 2
這是我用來使上述代碼正常工作的DateCount的實現...我想它與您的並不太相似:
public class DateCount implements Comparable<DateCount>{
private Date date = null;
private Long count = 0L;
public DateCount(Date datetime, Long count){
this.date = datetime;
this.count = count;
}
public void setDateTime(Date date){
this.date = date;
}
public Date getDate(){
return date;
}
public void setCount(long count){
this.count = count;
}
public long getCount(){
return count;
}
@Override
public int hashCode(){
return date.hashCode() + 459;
}
@Override
public boolean equals(Object o){
boolean result = false;
if (o instanceof DateCount){
DateCount other = (DateCount) o;
result = this.compareTo(other) == 0;
}
return result;
}
@Override
public int compareTo(DateCount other) {
if (this.date == null){
return other.getDate() == null ? 0 : -1;
} else {
return date.compareTo(other.getDate());
}
}
@Override
public String toString(){
return "DateCount: " + date.toString() + " - " + count;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.