根据字符串的优先级减少对象列表

Reduction of List of Objects based on priority of String

假设我有一个列表List<Foo> mylist = parseFromCSV();

哪里

parseFromCSV() 

returns Foo class 的对象列表。 Foo class 有她的私有属性:

private mailId;
private status;

...吸气剂和吸气剂...

可能是

中的一对对象
mylist: [{MailId=100, Status=BOUNCED, EMAIL=test@test.com},{MailId=100, Status=OPENED, EMAIL=test2@test.com}, {MailId=200, Status=CLICKED, EMAIL = test3@test.com}, {MailId=100, Status=HARDBOUNCED, EMAIL = test4@test.com}]

我的列表中确实可以有重复项,因为列出的对象代表解析为 Java 对象的 CSV 行。 每个 MailId 都有多个不同的可能状态反馈。

我感兴趣的是只检索我的一个 MailId 的一组可能状态中的 "important" 状态 并保存到我的数据库中。

OPENED > CLICKED > HARDBOUNCED > BOUNCED(状态的优先级)。

在我的示例中:对于 MailId= 100,我只会将 OPENED 状态保存到数据库中的状态列中。

实现此目标的好方法是什么?我应该创建一个新列表(集合吗?),其中包含每对过滤的 {MailId, Status(Prioritized)}, ... {MailIdN, StatusN(Prioritized)...} ?我们可以使用枚举或为我的 class Foo 的对象创建一个新的比较器来增加 String 的优先级吗?

使用 hibernate 对 mysql 数据库的持久化操作应该如下所示:

persistStatusIntoTable(String MailId, String Status(Taken only status based on priority))

感谢大家的帮助!

我在这里假设了几件事(可以很容易地改变)。首先 Status 是一个枚举(但是你可以对 String 做同样的事情)。

然后我使用 google 番石榴 Ordering 来简化 Comparator 的构建(没有它你也可以这样做)。

 Comparator<Status> c = Ordering.explicit(
            ImmutableList.of(Status.OPENED, Status.CLICKED, Status.HARDBOUNCED, Status.BOUNCED));

    List<Foo> list = Stream.of(new Foo(Status.BOUNCED, 57), new Foo(Status.OPENED, 57),
            new Foo(Status.CLICKED, 58), new Foo(Status.BOUNCED, 57),
            new Foo(Status.HARDBOUNCED, 58))
            .collect(Collectors.groupingBy(Foo::getId,
                    Collectors.mapping(Foo::getStatus, Collectors.toCollection(() -> new PriorityQueue<>(c)))))
            .entrySet()
            .stream()
            .map(e -> new Foo(e.getValue().remove(), e.getKey()))
            .collect(Collectors.toList());

    System.out.println(list); // [id = 57 status = OPENED, id = 58 status = CLICKED]

我们的想法是创建一个 Comparator 来定义您的 Statuses 的顺序;然后使用该比较器填充 PriorityQueue (对于某些 ID);最终我只对第一个感兴趣——正如你所说的最重要(根据比较器,这是第一个)。

这里是使用 StringStatusenum 的版本:

 Comparator<String> c = Ordering.explicit(
            ImmutableList.of("OPENED", "CLICKED", "HARDBOUNCED", "BOUNCED"));

    List<Foo> list = Stream.of(new Foo("BOUNCED", 57), new Foo("OPENED", 57),
            new Foo("CLICKED", 58), new Foo("BOUNCED", 57),
            new Foo("HARDBOUNCED", 58))
            .collect(Collectors.groupingBy(Foo::getId,
                    Collectors.mapping(Foo::getStatus, Collectors.toCollection(() -> new PriorityQueue<>(c)))))
            .entrySet()
            .stream()
            .map(e -> new Foo(e.getValue().remove(), e.getKey()))
            .collect(Collectors.toList());

如果您不想使用第 3 方库并且不想使用枚举 class:

// initialization which you will have to do once somewhere in your code
List<String> ordering = Arrays.asList("OPENED", "CLICKED", "HARDBOUNCED", "BOUNCED");
Map<String, Integer> priorityMap = IntStream.range(0, ordering.size()).boxed()
        .collect(Collectors.toMap(ordering::get, i -> i));

// example input
List<Foo> myList = Arrays.asList(
        new Foo("100", "BOUNCED"), new Foo("100", "OPENED"),
        new Foo("101", "BOUNCED"), new Foo("101", "HARDBOUNCED"), new Foo("101", "BOUNCED"));

// determine foo objects that should be persisted 
Collection<Foo> toBePersisted = myList.stream()
        .filter(t -> priorityMap.containsKey(t.getStatus()))
        .collect(Collectors.toMap(Foo::getMailId, t -> t,
                BinaryOperator.minBy(Comparator.comparing(t -> priorityMap.get(t.getStatus())))))
        .values();

这段代码的作用是:

  • 设置一个将状态映射到优先级的映射(较低的 int = 较高的优先级)
  • 过滤掉状态无效的 Foo 实例
  • 按 mailId 对 Foo 实例进行分组
  • 保持每个组具有最小优先级整数(=最高优先级)的 Foo 实例
  • 获取结果地图的值