【问题标题】:Calculate occurrence of property in a list of objects and convert objects to list of new objects with that counter计算对象列表中属性的出现,并使用该计数器将对象转换为新对象列表
【发布时间】:2021-12-27 16:23:28
【问题描述】:

我有一个Person 对象列表。 idPerson 类的属性之一。该列表可以包含具有相同 id 和不同其他属性的 Person 的重复项。

现在我需要计算相同id 的出现次数,然后将按timestamp 排序的分组Persons 转换为另一个具有occurrences 属性的对象。

我想出了这样的东西,我想知道是否有任何方法可以简化这个过程:

List<Person> persons = Arrays.asList(new Person("A", "2021-12-27"), new Person("B", "2021-12-26"), new Person("A", "2021-12-25"));
Map<String, Long> personToOccurrence = persons
    .stream()
    .collect(Collectors.groupingBy(Person::getUserName, Collectors.counting()));
List<NewClass> convertedPersonsWithOccurrences = persons
    .stream()
    .filter(distinctByKey(Person::getUserName))
    .map(i -> convertToNewClass(i, personToOccurrence.get(i.getUserName())))
    .collect(Collectors.toList());
class Person {
   String id;
   Date timestamp;
}
                    
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

所以在convertedPersonsWithOccurrences 我希望有:

NewClass("A", "2021-12-27", 2)
NewClass("B", "2021-12-26", 1)

其中最后一个属性是id 属性在persons 列表中的出现。

编辑:

总的来说,这些类已被简化。在实际情况下,convertToNewClass 应该接受具有多个字段的整个对象并将其转换为新类。所以这就是为什么我给出了传递整个 Person 对象和事件的例子。

【问题讨论】:

    标签: java lambda java-stream


    【解决方案1】:

    您可以将toMap 收集器与合并功能一起使用。在合并函数中,您需要比较 Timestamp 属性并增加 count 值。

    使用LocalDate 代替Date

     persons.stream()
                .collect(Collectors.toMap(Person::getId,
                        v -> new NewClass(v.id, v.getTimestamp(), 1l),
                        (o1, o2) -> {
                            if (o1.getTimestamp().isAfter(o2.getTimestamp())) {
                                o1.setCount(o1.getCount() + 1l);
                                return o1;
                            } else {
                                o2.setCount(o2.getCount() + 1l);
                                return o2;
                            }
                        })).values();
    

    【讨论】:

    • 感谢您发布此信息。您如何看待肖恩发布的答案?您的只有一个流,但之后会更新计数器。
    【解决方案2】:

    由于您有一个用户 ID 映射,您可以通过查看映射的键来跳过第二次计算中的不同内容,根据定义这些键是不同的。

    如果您使用基本groupingBy() 而不是添加下游counting() 收集器,以便获得每组Persons 的列表,它将使获取每组的最新(或最旧)时间戳变得容易。

    独立的 Java 17+ 示例:

    import java.util.*;
    import java.util.stream.*;
    
    public class Demo {
        private static record Person(String id, Date timestamp) {}
        private static record NewClass(String id, Date timestamp, int count) {}
    
        private static Date makeDate(int year, int month, int day) {
            Calendar c = Calendar.getInstance();
            c.clear();
            c.set(year, month - 1, day);
            return c.getTime();
        }
    
        public static void main(String[] args) {
            List<Person> persons = List.of(new Person("A", makeDate(2021, 12, 27)),
                                           new Person("B", makeDate(2021, 12, 26)),
                                           new Person("A", makeDate(2021, 12, 25)));
            Map<String, List<Person>> groupedPersons =
                persons.stream().collect(Collectors.groupingBy(Person::id));
            List<NewClass> convertedPersonsWithOccurences =
                groupedPersons.entrySet().stream()
                .map(e -> new NewClass(e.getKey(),
                                       e.getValue().stream()
                                        .max((a, b) -> a.timestamp.compareTo(b.timestamp))
                                        .orElseThrow()
                                        .timestamp,
                                       e.getValue().size()))
                .collect(Collectors.toList());
            System.out.println(convertedPersonsWithOccurences);
        }
    }
    

    展示

    [NewClass[id=A, timestamp=Mon Dec 27 00:00:00 PST 2021, count=2], NewClass[id=B, timestamp=Sun Dec 26 00:00:00 PST 2021, count=1]]
    

    运行时。

    【讨论】:

    • 感谢您发布此信息。我更新了我的问题,在那里我提供了传递整个对象所需的信息。所以我根据我的需要调整了你的代码。但问题是你的答案比哈迪的例子有优势吗?你的有 3 个流,只有一个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 2019-12-16
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多