使用流将一个类对象转换为另一个类对象

时间:2020-01-29 12:32:37

标签: java java-stream

我知道这个问题可能会引起误解,如果可能有人可以纠正它,我不确定在这种情况下如何提出问题。

我正在尝试将X类转换为Y类(此处,Y类包含X类的字段,但是以不同的方式,例如:X类内部的 Integer a, b;转换为Map<a, b> Y类中,而其他变量保持不变。),

在Java 8中使用流。 我正在尝试将最终对象作为json 返回到UI 部分。 该项目在 spring boot 中完成。 X类和Y都包含相同的对象,但Y类是使X类与众不同 我对流不熟悉。

X类

public class X {

private final String thumbnailUrl;
private final Integer duration;
private final String contentId;
private final Date reportDate;
private final Integer count;

public X(Report report, int count) {
    this.thumbnailUrl = report.getContent().getThumbnailUrl();
    this.duration = report.getContent().getDuration();
    this.contentId = report.getContent().getContentId();
    this.reportDate = report.getReportDate();
    this.count = count;
}

public String getThumbnailUrl() {
    return thumbnailUrl;
}

public Integer getDuration() {
    return duration;
}

public String getContentId() {
    return contentId;
}

public Date getReportDate() {
    return reportDate;
}

public Integer getCount() {
    return count;
}    

}

Y类

public class Y {

private final String thumbnailUrl;
private final Integer duration;
private final String contentId;
private final Map<Date, Integer> contentList;

public Y(X x, Map<Date, Integer> contentList) {
    this.thumbnailUrl = x.getThumbnailUrl();
    this.duration = x.getDuration();
    this.contentId = x.getContentId();
    this.contentList = contentList;
}

public String getThumbnailUrl() {
    return thumbnailUrl;
}

public Integer getDuration() {
    return duration;
}

public String getContentId() {
    return contentId;
}

public Map<Date, Integer> getContentList() {
    return contentList;
}

}

这是我目前从X班获得的

[
{
    "thumbnailUrl": "a",
    "duration": 12,
    "contentId": "CNT10",
    "reportDate": "2020-01-20",
    "count": 3
},
{
    "thumbnailUrl": "a",
    "duration": 12,
    "contentId": "CNT10",
    "reportDate": "2020-01-21",
    "count": 5
},
{
    "thumbnailUrl": "a",
    "duration": 12,
    "contentId": "CNT10",
    "reportDate": "2020-01-22",
    "count": 3
},
{
    "thumbnailUrl": "a",
    "duration": 12,
    "contentId": "CNT10",
    "reportDate": "2020-01-23",
    "count": 4
}
]

使用此代码并返回最终列表后,我在邮递员中得到了上述json。

List<X> x;
List<Y> y;

x = StreamSupport.stream(reportRepository
                .reportWithRoll(a, b, c).spliterator(), false)
                .map(report -> new X(report, report.getStartCount()))
                .collect(Collectors.toList());

我希望将其转换为如下所示的Y类内容。 如何使用Java流实现此目标?

[
    {
        "list": [
            {
                "2020-01-20": 3,
                "2020-01-21": 5,
                "2020-01-22": 3,
                "2020-01-23": 4
            }
        ],
        "thumbnailUrl": "a",
        "duration": 12,
        "contentId": "CNT10"
    }
]

我尝试使用此方法获取上述json格式,但最终获得了重复的数据(单个contentId重复)和多个contentId错误

y = x.stream().map(
                rep -> {
                    Map<Date, Integer> contentList = x.stream().collect(
                            Collectors.toMap(X::getReportDate, X::getCount)
                    );
                    Y yy = new Y(rep, contentList);
                    return yy;
                }
        ).distinct().collect(Collectors.toList());

我将常见的日期和计数:键值对组合为每个唯一的“ contentId”的单个“列表”(每个唯一的“ contentId”都有其专用的“ thumbnailUrl”和“ duration”,所以当我指的是“ contentId”是唯一的,它将包括“ thumbnailUrl”和“ duration”,其中只有日期和计数会是多个。

4 个答案:

答案 0 :(得分:1)

考虑到contentId会为输入中的任何thumbnailUrl带来durationX相同的值,您可以分两个步骤进行操作:

Map<String, X> contentIdLookUp = x.stream()
        .collect(Collectors.toMap(X::getContentId, Function.identity()));

List<Y> y = x.stream()
        .collect(Collectors.groupingBy(X::getContentId, 
                Collectors.toMap(X::getReportDate, X::getCount))))
        .entrySet().stream()
        .map(e -> new Y(contentIdLookUp.get(e.getKey()), e.getValue()))
        .collect(Collectors.toList());

答案 1 :(得分:1)

由于一个堆栈溢出answer,我发现了使用流本身的解决方案。

y = x.stream()
            .map(X::getContentId)
            .distinct()
            .map(
                    contentId -> {
                        return reportModifier(reportViews, contentId);
                    }
            ).collect(Collectors.toList());


private Y reportModifier(List<x> x, String contentId) {
    Map<Date, Integer> contentList = x.stream()
                                .filter(a -> a.getContentId().equals(contentId))
                                .collect(
                                        Collectors.toMap(X::getReportDate, X::getCount)
                                );

                        X rv = x.stream()
                                .filter(a -> a.getContentId().equals(contentId))
                                .findFirst()
                                .get();

                        Y yy = new Y(rv, contentList);
                        return yy;

}

我得到了以下json

[
{
    "thumbnailUrl": "a",
    "duration": 12,
    "contentId": "CNT10",
    "contentList": {
        "2020-01-21T18:30:00.000+0000": 3,
        "2020-01-20T18:30:00.000+0000": 3,
        "2020-01-22T18:30:00.000+0000": 3,
        "2020-01-19T18:30:00.000+0000": 3
    }
},
{
    "thumbnailUrl": "b",
    "duration": 12,
    "contentId": "CNT12",
    "contentList": {
        "2020-01-19T18:30:00.000+0000": 3
    }
},
{
    "thumbnailUrl": "c",
    "duration": 12,
    "contentId": "CNT11",
    "contentList": {
        "2020-01-21T18:30:00.000+0000": 3,
        "2020-01-20T18:30:00.000+0000": 3,
        "2020-01-19T18:30:00.000+0000": 3
    }
}
]

答案 2 :(得分:0)

如果我理解这个问题,那么您只是将所有X对象收集到一个Y对象中?

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html

public class YCollector<X, Y, Y> {
    public Supplier<Y> supplier() {
         return () -> new Y();   
    }

    public BiConsumer<X, Y> accumulator {
        return (x, y) -> {
            y.list.add(x.thumbnailUrl);
            y.duration += x.duration;
            ...
            return y;
        }
    }

    public BinaryOperator<Y> combiner {
        return (y1, y2) -> {
             return y1.merge(y2);
        }
    }

    public Function<Y, Y> finisher() {
        return (y) -> y;
    }
}

您实际上只是: -创建一个新的Y -将所有X值滚动到Y -返回最后的Y

修改

我刚刚注意到您希望最终结果是List<Y>而不是Y。您可以使用同一件事,只需要相应地更新方法即可进行处理。可能使用

class YCollector<X, Map<String,Y>, List<Y>> {
    // Update methods to combine into Map<ContentId, Y> and then finalize with map values.
}

答案 3 :(得分:0)

为什么会变得复杂?使用Map Struts ...您可以在编译时将一个对象转换为另一个对象。这是一个非常不错的库,并且已经在Spring中进行了测试和使用