首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java8按自定义值分组自定义映射值

问java8按自定义值分组自定义映射值
EN

Stack Overflow用户
提问于 2018-05-17 18:44:54
回答 3查看 374关注 0票数 0

java8

代码语言:javascript
复制
public class CustomDate{    
    LocalDateTime datetime;   
}

List<CustomDate>  list = // 2 dates with multiple times

我想按日对日期进行分组,并按下列时间对值进行分组,以CustomDate作为值?

代码语言:javascript
复制
Map<LocalDate, List<CustomDate>> map = 
         list.stream().groupingBy(d-> d.datetime.toLocalDate())

任何帮助都是非常感谢的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-05-19 23:45:25

代码语言:javascript
复制
public class Dates {

    private static List< CustomDate > list = new ArrayList<>(  );

    public static void main( String[] args ) {

        Map< LocalDate, List< LocalTime > > result2 = list.stream()
            .map( CustomDate::getDatetime )
            .collect(
                HashMap::new,
                Dates::accept,
                Dates::merge
            );

    }

    private static void accept( HashMap< LocalDate, List< LocalTime > > map, LocalDateTime date ) {

        map.putIfAbsent( date.toLocalDate( ), new ArrayList<>())
           .add( date.toLocalTime( ) );
    }

    private static void merge( Map< LocalDate, List< LocalTime > > map1, Map< LocalDate, List< LocalTime > > map2 ) {

        map2.forEach( (date,timeList) -> {
            map1.merge( date, timeList, ( l1, l2 ) -> {
                l1.addAll( l2 );
                return l1;
            } );
        });

    }
}

或者简单地说:

代码语言:javascript
复制
Map< LocalDate, List< LocalTime > > result2 = list.stream()
    .map( CustomDate::getDatetime )
    .collect(
        HashMap::new,
        (map,date) -> {
             map.putIfAbsent( date.toLocalDate( ), new ArrayList<>(   )).add( date.toLocalTime( ) );
        },
        (map1, map2) -> {
            map2.forEach( (date,timeList) -> {
                map1.merge( date, timeList, ( l1, l2 ) -> {
                    l1.addAll( l2 );
                    return l1;
                } );
            }); 
        }
    );

这样做的方式不是声明性地调用3次收集器静态方法,而是提供了更多的控制来命令行为,比如为数组使用初始大小、使用特定列表等等,而不会丢失声明式样式带来的糖。

代码语言:javascript
复制
Map< LocalDate, List< LocalTime > > result2 = list.stream()
    .map( CustomDate::getDatetime )
    .collect(
        TreeMap::new,
        (map,date) -> {
             map.putIfAbsent( date.toLocalDate( ), new ArrayList<>( 800  )).add( date.toLocalTime( ) );
        },
        (map1, map2) -> {
            map2.forEach( (date,timeList) -> {
                map1.merge( date, timeList, ( l1, l2 ) -> {
                    l1.addAll( l2 );
                    return l1;
                } );
            }); 
        }
    );

当然,如果默认行为是可以接受的,这就简单得多:

代码语言:javascript
复制
    Map<LocalDate, List<LocalTime>> result = list.stream()
            .map( CustomDate::getDatetime )
            .collect(groupingBy(LocalDateTime::toLocalDate,
                     mapping(LocalDateTime::toLocalTime,toList())));

另一种方法是定义您自己的收集器,这是我通常喜欢的。通过这样做,您可以同时获得控制和对逻辑进行声明编码的能力,并在需要时进行重用。

这将使您的代码减少到:

代码语言:javascript
复制
Map< LocalDate, List< LocalTime > > result2 = list.stream()
            .collect(
                    customDateCollector()
            );

如果你有这样的东西:

代码语言:javascript
复制
class CustomDateCollector implements Collector<CustomDate, Map< LocalDate, List< LocalTime > >, Map< LocalDate, List< LocalTime > >> {

    @Override
    public Supplier< Map< LocalDate, List< LocalTime > > > supplier( ) {

        return HashMap::new;
    }

    @Override
    public BiConsumer< Map< LocalDate, List< LocalTime > >, CustomDate > accumulator( ) {
        int goodStartUsingProblemKnowledge = 30;
        return (map, customDate) -> map.putIfAbsent( customDate.getDatetime().toLocalDate(), new ArrayList<>( goodStartUsingProblemKnowledge) )
                                       .add(  customDate.getDatetime().toLocalTime() );
    }

    @Override
    public BinaryOperator< Map< LocalDate, List< LocalTime > > > combiner( ) {

        return (map1, map2) -> {
                map2.forEach( (date,timeList) -> {
                    map1.merge( date, timeList, ( list1, list2 ) -> {
                        list1.addAll( list2 );
                        return list1;
                    } );
                });
                return map1;
        };
    }

    @Override
    public Function< Map< LocalDate, List< LocalTime > >, Map< LocalDate, List< LocalTime > > > finisher( ) {

        return Function.identity();
    }

    @Override
    public Set< Characteristics > characteristics( ) {

        return Collections.unmodifiableSet( EnumSet.of( IDENTITY_FINISH, UNORDERED,CONCURRENT) );
    }

    public static CustomDateCollector customDateCollector(){
        return new CustomDateCollector();
    }
}
票数 0
EN

Stack Overflow用户

发布于 2018-05-17 18:49:33

您似乎希望按日期进行分组,并将映射值作为LocalTime而不是CustomDate。

代码语言:javascript
复制
Map<LocalDate, List<LocalTime>> result = list.stream()
                .collect(Collectors.groupingBy(e -> e.getDatetime().toLocalDate(),
                        Collectors.mapping(e -> e.getDatetime().toLocalTime(),
                                Collectors.toList())));
票数 4
EN

Stack Overflow用户

发布于 2018-05-17 19:14:22

正如Aominè的回答一样,您应该使用Collectors.groupingBy()。但我建议你做一些额外的步骤。

1使用一些通用代码四值化创建GroupUtils类:

代码语言:javascript
复制
public final class GroupUtils {

    public static <K, V> Map<K, List<V>> groupMultipleBy(Collection<V> data, Function<V, K> classifier) {
        return groupMultipleBy(data, classifier, Function.identity());
    }

    public static <K, V, S> Map<K, List<S>> groupMultipleBy(Collection<V> data, Function<V, K> classifier, Function<V, S> mapper) {
        return Optional.ofNullable(data).orElse(Collections.emptyList()).stream()
                       .collect(Collectors.groupingBy(classifier, Collectors.mapping(mapper, Collectors.toList())));
    }
}

这是我的一个项目的例子。这里我有更多类似的方法。

2在本地文件中,创建具体的方法,使客户端代码的可读性大大提高。

代码语言:javascript
复制
class Client {

    public static void main(String... args) {
        List<CustomDate> list = Collections.emptyList();
        Map<LocalDateTime, List<CustomDate>> map = groupByDatetime(list);
    }

    private static Map<LocalDateTime, List<CustomDate>> groupByDatetime(List<CustomDate> list) {
        return GroupUtils.groupMultipleBy(list, CustomDate::getDatetime);        
    }
}

我相信这是一些更多的代码,但比:

代码语言:javascript
复制
Map<LocalDate, List<LocalTime>> result = list.stream()
                .collect(Collectors.groupingBy(e -> e.getDatetime().toLocalDate(),
                        Collectors.mapping(e -> e.getDatetime().toLocalTime(),
                                Collectors.toList())));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50398518

复制
相关文章

相似问题

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