【问题标题】:Java 8 Streams Grouping by an Optional AttributeJava 8 流按可选属性分组
【发布时间】:2016-10-21 14:39:23
【问题描述】:

我正在尝试对属性中的计算值进行分组。计算的值是可选的 - 更清楚一点,他是一个简化的例子:

class Foo: 
   int id;
   Group group;
   .. some other stuff

class Group: 
   String groupId;
   ... (some other stuff)

class SomeName:
   String someAttribute;

class Converter:
   public Optional<SomeName> getSomenameFromGroup(Group)

我无法更改 Converter 中的方法,因为它不属于我。

我有一个 Foo 列表,我想通过 SomeName 的“someAttribute”进行过滤。

例如,我有这样的事情:

Map<String, List<Foo>> fooBySomeName = 
  fooList.stream().collect(Collectors
    .groupingBy(foo -> {
        Optional<SomeName> name = 
           converter.getSomenameFromGroup(foo.getGroup.getGroupId());
        return name.isPresent() ? name.get().someAttribute() : "";
    }));

但问题是,如果 groupingBy 语句中不存在名称,我不希望地图中出现任何内容。我有这样的事情:

fooBySomeNames.remove("")

我认为可以从按该键分组的地图中删除任何内容,但是在 groupingBy 语句中是否有更清洁或更正确的方法来执行此操作?

【问题讨论】:

    标签: java java-stream optional collectors


    【解决方案1】:

    您可以使用过滤器删除条目,如下所示。

    Map<String, List<Foo>> fooBySomeName = fooList.stream()
        .filter(foo -> fooToSomeAttribute(foo).isPresent())
        .collect(Collectors.groupingBy(foo -> fooToSomeAttribute(foo).get()));
    
    private static Optional<String> fooToSomeAttribute(Foo foo)
    {
        return Optional.ofNullable(foo)
            .map(Foo::getGroup)
            .flatMap(new Converter()::getSomenameFromGroup)
            .map(SomeName::getSomeAttribute);
    }
    

    或者,使用 pair 对象,您可以避免为每个 Foo 重复计算 someAttribute:

    Map<String, List<Foo>> fooBySomeName = fooList.stream()
        .filter(Objects::nonNull)
        .map(FooAndSomeAttribute::new)
        .filter(pair -> pair.getSomeAttribute().isPresent())
        .collect(Collectors.groupingBy(
            pair -> pair.getSomeAttribute().get(),
            Collectors.mapping(
                FooAndSomeAttribute::getFoo, 
                Collectors.toList())));
    
    private static class FooAndSomeAttribute
    {
        private final Foo foo;
        private final Optional<String> someAttribute;
    
        public FooAndSomeAttribute(Foo foo)
        {
            this.foo = foo;
            this.someAttribute = Optional.ofNullable(foo)
                .map(Foo::getGroup)
                .flatMap(new Converter()::getSomenameFromGroup)
                .map(SomeName::getSomeAttribute);
        }
    
        public Foo getFoo() 
        {
            return foo;
        }
    
        public Optional<String> getSomeAttribute() 
        {
            return someAttribute;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-05
      • 2014-12-21
      • 1970-01-01
      • 2019-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多