首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用流按多个属性分组和排序: Java 8

使用流按多个属性分组和排序: Java 8
EN

Stack Overflow用户
提问于 2020-08-15 08:06:59
回答 2查看 139关注 0票数 2

我有MainEntity的名单

代码语言:javascript
复制
public class MainEntity {
private String keyword;
private double cost;
private String company;
}

我有CompanyEntity

代码语言:javascript
复制
public class CompanyEntity {
    private double cost;
    private String company;
    }

我正在尝试将我的列表转换为Map<String,List<CompanyEntity>>,其中的键将是keywordList<CompanyEntity>将有所有成本的平均值,并进行排序。我正试图在流和Java 8中完成它。

对于一个特定的关键字作为输入,我正在这样做。

代码语言:javascript
复制
List<MainEntity> entityList = keyWordMap.get(entity.getKeyword());
        entityList.add(entity);
        keyWordMap.put(entity.getKeyword(), entityList);

Map<String, Double> average = (keyWordMap.get(keyword)).stream()
            .collect(groupingBy(MainEntity::getCompany,
                    Collectors.averagingDouble(MainEntity::getCtr)));
    result.put(keyword, new ArrayList<>());

    for (Map.Entry<String, Double> entity : average.entrySet()) {
        result.get(keyword).add(new CompanyEntity(entity.getKey(), entity.getValue()));
    }

但我试着为所有关键词创建一个地图。是否有可能再次迭代整个列表?目前,keyowordMapMap<String,MainEntity>类型的,我是通过迭代MainEntity列表来实现的,但是我想要Map<String,List<MainEntity>>

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-15 08:16:45

首先,制作一个keyWordMap

代码语言:javascript
复制
Map<String, List<MainEntity>> keyWordMap = 
            mainEntityList
            .stream()
            .collect(Collectors.groupingBy(MainEntity::getKeyword));

然后迭代映射,对于每个关键字,可以根据平均值直接获取CompanyEntity排序列表,并使用map()转换数据并将其作为列表收集,然后放入result中。

代码语言:javascript
复制
Map<String,List<CompanyEntity>> result = ....
for (Map.Entry<String, List<MainEntity> entry : keyWordMap.entrySet()) {
    List<CompanyEntity> list = entry.getValue().stream()
                .collect(groupingBy(MainEntity::getCompany,
                        Collectors.averagingDouble(MainEntity::getCtr)))
                .entrySet()
                .stream()
                .sorted(Comparator.comparing(e -> e.getValue()))
                .map(e -> new CompanyEntity(e.getKey(), e.getValue()))
                .collect(Collectors.toList());
    result.put(entry.getKey(), list);
}

或者你想一蹴而就

代码语言:javascript
复制
Map<String,List<CompanyEntity>> mapData = 
           mainEntityList
            .stream()
            .collect(Collectors.groupingBy(MainEntity::getKeyWord,
                     Collectors.groupingBy(MainEntity::getCtr,
                        Collectors.averagingDouble(MainEntity::getCtr))))
            .entrySet()
            .stream()
            .collect(Collectors.toMap(m -> m.getKey(),
                 m -> m.entrySet()
                       .stream()
                       .sorted(Comparator.comparing(e -> e.getValue()))
                       .map(e -> new CompanyEntity(e.getKey(), e.getValue()))
                       .collect(Collectors.toList())));
票数 3
EN

Stack Overflow用户

发布于 2020-08-15 08:47:41

另一个答案在最初误解了问题后完全改变了它的答案,并且在良好的StackOverflow精神中它吸引了第一个向上的选票,所以现在被接受并且被最高的支持。但是在代码中还有几个步骤显示了正在发生的事情:

这会让你得到这样的结果:

代码语言:javascript
复制
import java.io.IOException;
import java.util.AbstractMap.SimpleEntry;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Value;

public class CompanyEntityStackOverflowQuestion {

    public static void main(String[] args) throws IOException {

        //setup test data
        MainEntity one = new MainEntity("key1", 10D, "company1");
        MainEntity two = new MainEntity("key2", 5D, "company2");
        MainEntity three = new MainEntity("key1", 7D, "company3");
        MainEntity four = new MainEntity("key2", 3D, "company4");
        List<MainEntity> mainEntityList = List.of(one, two, three, four);

        //group list by keyword
        Map<String, List<MainEntity>> mainEntityByKeyword = mainEntityList.stream()
            .collect(Collectors.groupingBy(MainEntity::getKeyword));

        //map to companyEntity object
        Stream<SimpleEntry<String, List<CompanyEntity>>> mapped = mainEntityByKeyword.entrySet().stream()
            .map(entry -> new SimpleEntry<>(entry.getKey(), entry.getValue().stream().map(
                getCompanyListFunction()).collect(Collectors.toList())));

        //sort and calculate average
        Stream<SimpleEntry<String, CompanyEntityListWithStats>> mappedToListWithStats = mapped
            .map(entry -> new SimpleEntry<>(entry.getKey(),
                new CompanyEntityListWithStats(entry.getValue().stream().mapToDouble(company -> company.cost).average().orElse(0D), //or use Collectors.averagingDouble(company -> company.cost))
                    sortList(entry.getValue()))));

        //collect back to map
        Map<String, CompanyEntityListWithStats> collect = mappedToListWithStats
            .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

        //show result
        System.out.println(collect);
    }

    //sort by cost
    private static List<CompanyEntity> sortList(List<CompanyEntity> list) {
        list.sort(Comparator.comparing(company -> company.cost));
        return list;
    }

    //map MainEntity to CompanyEntity
    private static Function<MainEntity, CompanyEntity> getCompanyListFunction() {
        return mainEntity -> new CompanyEntity(mainEntity.cost, mainEntity.company);
    }

    @Value
    public static class MainEntity {

        public String keyword;
        public double cost;
        public String company;
    }

    @Value
    public static class CompanyEntity {

        public double cost;
        public String company;
    }

    @Value
    public static class CompanyEntityListWithStats {

        public double average;
        public List<CompanyEntity> companyList;
    }


}

输出:{key1=CompanyEntityStackOverflowQuestion.CompanyEntityListWithStats(average=8.5, companyList=[CompanyEntityStackOverflowQuestion.CompanyEntity(cost=7.0, company=company3), CompanyEntityStackOverflowQuestion.CompanyEntity(cost=10.0, company=company1)]), key2=CompanyEntityStackOverflowQuestion.CompanyEntityListWithStats(average=4.0, companyList=[CompanyEntityStackOverflowQuestion.CompanyEntity(cost=3.0, company=company4), CompanyEntityStackOverflowQuestion.CompanyEntity(cost=5.0, company=company2)])}

您可能可以跳过一些步骤,这只是快速打印出来。当然,你可以用内嵌的东西来让它看起来更短/更干净,但是这种格式显示了正在发生的事情。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63423924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档