#java #collections #java-8 #java-stream
#java #Коллекции #java-8 #java-stream
Вопрос:
У меня есть список основных объектов
public class MainEntity {
private String keyword;
private double cost;
private String company;
}
и у меня есть CompanyEntity
public class CompanyEntity {
private double cost;
private String company;
}
Я пытаюсь преобразовать свой список в, Map<String,List<CompanyEntity>>
где key будет keyword
и List<CompanyEntity>
будет иметь среднее значение всех затрат и также отсортирован. Я пытаюсь сделать это в stream и Java 8.
Для определенного ключевого слова в качестве входных данных я делаю это.
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()));
}
Но я пытаюсь создать карту для всех ключевых слов. Возможно ли или имеет смысл повторить весь список заново?
В настоящее время keyowordMap
имеет тип Map<String,MainEntity>
, который я сделал, повторив список MainEntity
, но я хочу Map<String,List<MainEntity>>
.
Ответ №1:
Сначала создайте keyWordMap
Map<String, List<MainEntity>> keyWordMap =
mainEntityList
.stream()
.collect(Collectors.groupingBy(MainEntity::getKeyword));
Затем повторите отображение, для каждого ключевого слова вы можете напрямую получить список CompanyEntity
сортировки по среднему значению и использования map()
для преобразования данных и сбора в виде списка, затем поместите в result
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);
}
Или вы хотите сделать это одним выстрелом
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())));
Комментарии:
1. Я пытаюсь создать
Map<Keyword, List<CompanyEntity>>
, а не для одного ключевого слова.2. @AlokShukla вы показываете код только для одного конкретного ключевого слова, и у вас уже есть
keyWordMap
право? Вам также нужен списокMainEntity
tokeyWordMap
?3. То, что у меня есть,
MainEntity("keyword1",1,"company 1"); MainEntity("keyword2",1,"company 1"); MainEntity("keyword1",1,"company 2"); MainEntity("keyword2",1,"company 2");
что я сделал в keyWord map, было просто итерацией по списку, который не агрегируется. Это похоже,Map<String, MainEntity>
но я пытаюсь сделатьMap<String, List<Entity>>
. Также отредактирую сообщение, чтобы сделать его более понятным4. @AlokShukla Также добавлено одноразовое решение.
5. И вам нужно повторить список еще раз, просто повторите map и получите список объектов для ключевого слова и преобразуйте в список CompanyEntity
Ответ №2:
Другой ответ полностью изменил свой ответ после первоначального неправильного понимания вопроса, и в хорошем настроении StackOverflow он привлек первое одобрение, поэтому теперь принят и получил наибольшее количество голосов. Но в этом коде есть еще несколько шагов, показывающих, что происходит:
Это должно дать вам результат:
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)])}
Возможно, вам удастся пропустить некоторые шаги, это просто быстро вводится. Вы, конечно, можете встроить материал, чтобы он выглядел намного короче / чище, но этот формат показывает, что происходит.