根据String的优先级减少对象列表

时间:2017-03-22 23:34:04

标签: java hibernate data-structures java-8 reduce

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

哪里

parseFromCSV() 

返回Foo类对象的列表。 Foo类有她的私人属性:

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都有多种不同的反馈状态。

我感兴趣的是,只检索&#34; important&#34;状态在我的一组MailId的可能状态集中并持久存储到我的数据库中。

已打开&gt;点击&gt; HARDBOUNCED&gt; BOUNCED(状态的优先级)。

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

实现这一目标的好方法是什么?我应该创建一个新的List(Set?),其中包含已过滤{MailId, Status(Prioritized)}, ... {MailIdN, StatusN(Prioritized)...}的每一对吗?我们可以使用Enumerations为String添加优先级,还是为Foo类的对象创建一个新的比较器?

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

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

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

我在这里假设了几件事(可以很容易地改变)。首先Status是枚举(例如,您可以对String执行相同的操作)。

然后我使用google guava 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来定义Status es的顺序;然后使用该比较器填充PriorityQueue(对于某些id);最终我只对第一个感兴趣 - 你称之为重要(根据比较者的说法,这是第一个)。

以下是使用Stringenum Status的版本:

 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());

答案 1 :(得分:2)

如果您不想使用第三方库而又不想使用枚举类:

// 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();

此代码的作用是:

  • 设置将状态映射到优先级的映射(lower int = higher priority)
  • 过滤具有无效状态的Foo实例
  • 通过mailId
  • 分组Foo实例
  • 保持每个组具有最小优先级整数(=最高优先级)的Foo实例
  • 获取结果地图的值