使用Java 8 Lambda表达式,通过内部列表的属性过滤对象列表

时间:2018-08-24 22:36:27

标签: java datetime lambda max filtering

我是 Java lambda表达式的新手,并且一直在努力解决以下问题:

我正在尝试将以下“活动”对象列表过滤为具有最近开始时间的单个“活动”:

{
     Name: "activity1"
     Id: "abc-123"
     Fields: [
          { key: "startTime", value: "2018-08-24T12:00:01" },
          { key: "foo", value: "bar" },
          { key: "baz", value: "zoop" }
     ]
},
{
     Name: "activity2"
     Id: "def-456"
     Fields: [
          { key: "bat", value: "zap" },
          { key: "startTime", value: "2018-08-23T12:00:01" },
          { key: "cat", value: "dog" }
     ]
},
{
     Name: "activity3"
     Id: "ghi-789"
     Fields: [
          { key: "flim", value: "flam" },
          { key: "boop", value: "bop" },
          { key: "startTime", value: "2018-08-22T12:00:01" }
     ]
}

基本上,每个对象都有一个内部的字段列表,这些字段没有特定顺序显示,我想根据具有最大日期的“ startTime”字段将父集合过滤到一项。

对于示例数据,目标是仅返回名称为“ activity1”的对象。请注意,字段对象在我的数据中没有按照特定的顺序出现。另外,如果一个活动的startTime与另一个活动的startTime相匹配,则代码应采用集合中第一个出现的项。

假设活动和字段在列表中,并且我的Activity类上有获取方法/设置方法,这就是我开始的内容,但是我知道这是不正确的:

activities().stream().filter(activity ->  
    activity.getFields().stream()
            .filter(field -> field.getKey().equals("startTime"))
            .max((field1, field2) -> {
                Date date1 = Date.from(Instant.parse(field1.getValue()));
                Date date2 = Date.from(Instant.parse(field2.getValue()));
                return date1.compareTo(date2);
            }).isPresent()
).findAny().get();

任何帮助或我应如何解决此问题的示例,将不胜感激。谢谢!


编辑1: 我正在使用的实际ActivityField类是从第3方库中检索的,不是我自己设计的。以下是它们的外观概念:

public class Activity {
     private String id;
     private String name;
     private List<Field> fields;

     public String getId() {
         return id;
     }

     public void setId(String id) {
         this.id = id;
     }

     public String getName() {
         return name;
     }

     public void setName(String name) {
         this.name = name;
     }

     public List<Field> getFields() {
         return fields;
     }

     public void setFields(List<Field> fields) {
         this.fields = fields;
     }
 }

public class Field {
     private String key;
     private String value;

     public String getKey() {
         return key;
     }

     public void setKey(String key) {
         this.key = key;
     }

     public String getValue() {
         return value;
     }

     public void setValue(String value) {
         this.value = value;
     }
 }

1 个答案:

答案 0 :(得分:3)

您可能想定义一个提取日期的函数,然后使用Collectors.maxBy。例如:

// Somewhere in your class:
Instant startDate(Activity activity) {
  return activity.getFields()
    .stream()
    .filter(field -> field.getKey().equals("startTime"))
    .map(field -> Instant.parse(field.getValue()))
    .findAny()
    .get();
}

// .. and then to use it:
Optional<Activity> maxStartDateActivity = activities()
    .stream()
    .max(Comparator.comparing(MyClass::startDate));

旁注:您可能不应该以自己的方式表示数据。为您的Activity值定义一个接口是值得的麻烦,它使您可以执行诸如将已解析的开始时间作为单个调用进行操作,然后可以在流管道中使用它。这样做将有助于将活动的表示方式与您要对它们进行的操作分离开来,这将使您的整个程序更易于阅读,更易于添加更多功能,并且将来更容易更改。