簡體   English   中英

如何在Java 8中合並不同的流

[英]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只是解析的方式StringDate

更新 -這是我到目前為止提出的。 雖然在.map調用中流過List<Object[]>似乎並不自然,不確定是否有更好的方法。 我引入了自己的Tuple<X, Y>類,因為在沒有訪問器方法的情況下,在流中使用Object[]不能很好地工作。 同樣在最后兩行中,我正在創建一個帶有ComparatorTreeSet ,以便可以按日期對數據進行排序。 我不認為這是最好的方法,但是我嘗試調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM