当前位置: 首页 > 知识库问答 >
问题:

Java8:用Lambda筛选和比较2个列表

谢烨烨
2023-03-14

任务:

    null
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

public class LambdaFilter
{
    public static void main(final String[] args)
    {
        final LambdaFilter lf = new LambdaFilter();
        lf.start();
    }

    private void start()
    {
        final List<Entry> list1 = Arrays.asList(
                                                new Entry(15, new DateTime(2012, 6, 29, 0, 0, 0, 0)),
                                                new Entry(101, new DateTime(2012, 3, 12, 0, 0, 0, 0)),
                                                new Entry(101, new DateTime(2012, 3, 12, 0, 0, 0, 0)),
                                                new Entry(68691, new DateTime(2015, 2, 12, 0, 0, 0, 0)),
                                                new Entry(68691, new DateTime(2015, 2, 12, 0, 0, 0, 0)),
                                                new Entry(68691, new DateTime(2015, 5, 01, 0, 0, 0, 0)),
                                                new Entry(70738, new DateTime(2016, 1, 26, 0, 0, 0, 0)));
        final List<Entry> list2 = Arrays.asList(
                                                new Entry(15, new DateTime(2012, 6, 29, 0, 0, 0, 0)),
                                                new Entry(101, new DateTime(2012, 3, 12, 0, 0, 0, 0)),
                                                new Entry(68691, new DateTime(2015, 2, 12, 0, 0, 0, 0)),
                                                new Entry(68691, new DateTime(2015, 2, 12, 0, 0, 0, 0)),
                                                new Entry(70738, new DateTime(2015, 7, 30, 0, 0, 0, 0)));

        System.out.println(list1);
        System.out.println(list2);

        // MAIN-GOAL: Get a list of ID's from list1 which have a higher Date or doesnt exists in list2

        // Filter list1 so every ID is unique (with highest Date)
        final Map<Integer, DateTime> list1UniqueIdMap = new HashMap<Integer, DateTime>();
        for (final Entry e : list1)
        {
            if (!list1UniqueIdMap.containsKey(e.getId()))
            {
                list1UniqueIdMap.put(e.getId(), e.getDate());
            }
            else
            {
                final DateTime dateFromMap = list1UniqueIdMap.get(e.getId());
                if (e.getDate().isAfter(dateFromMap))
                {
                    list1UniqueIdMap.put(e.getId(), e.getDate());
                }
            }
        }

        // Filter list2 so every ID is unique (with highest Date)
        final Map<Integer, DateTime> list2UniqueIdMap = new HashMap<Integer, DateTime>();
        for (final Entry e : list2)
        {
            if (!list2UniqueIdMap.containsKey(e.getId()))
            {
                list2UniqueIdMap.put(e.getId(), e.getDate());
            }
            else
            {
                final DateTime dateFromMap = list2UniqueIdMap.get(e.getId());
                if (e.getDate().isAfter(dateFromMap))
                {
                    list2UniqueIdMap.put(e.getId(), e.getDate());
                }
            }
        }

        System.out.println(list1UniqueIdMap);
        System.out.println(list2UniqueIdMap);

        // Get List of ID's which are in list1 but not in list2, or, if they are in list2, if they have a higher date
        // Furthermore, the the ID's of list1 which have a higher count then in list2
        final Set<Integer> resultSet = new HashSet<Integer>();
        for (final Integer id : list1UniqueIdMap.keySet())
        {
            if (!list2UniqueIdMap.containsKey(id))
            {
                resultSet.add(id);
            }
            else
            {
                final DateTime dateList1 = list1UniqueIdMap.get(id);
                final DateTime dateList2 = list2UniqueIdMap.get(id);

                if (dateList1.isAfter(dateList2))
                {
                    resultSet.add(id);
                }
            }

            if (getCount(list1, id) > getCount(list2, id))
            {
                resultSet.add(id);
            }
        }

        // Result
        System.out.println(resultSet);
    }

    private int getCount(final List<Entry> list, final int id)
    {
        int count = 0;
        for (final Entry e : list)
        {
            if (e.getId() == id)
            {
                count++;
            }
        }
        return count;
    }

    private class Entry
    {
        private int id;
        private DateTime date;

        public Entry(final int id, final DateTime date)
        {
            this.id = id;
            this.date = date;
        }

        public int getId()
        {
            return id;
        }

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

        public DateTime getDate()
        {
            return date;
        }

        public String getFormattedLastChangeDat()
        {
            return DateTimeFormat.forPattern("dd.MM.yyyy").print(getDate());
        }

        public void setDate(final DateTime date)
        {
            this.date = date;
        }

        @Override
        public String toString()
        {
            return this.getClass().getSimpleName() + "[id: " + this.getId() + " , date: " + this.getFormattedLastChangeDat() + "]";
        }

    }
}

我的示例的输出:

List1
[
Entry[id: 15 , date: 29.06.2012], 
Entry[id: 101 , date: 13.03.2012], 
Entry[id: 101 , date: 13.03.2012],   
Entry[id: 68691 , date: 12.02.2015],   
Entry[id: 68691 , date: 12.02.2015],   
Entry[id: 68691 , date: 01.05.2015],   
Entry[id: 70738 , date: 26.01.2016]]

List2:  
[
Entry[id: 15 , date: 29.06.2012],  
Entry[id: 101 , date: 13.03.2012],  
Entry[id: 68691 , date: 12.02.2015],   
Entry[id: 68691 , date: 12.02.2015],   
Entry[id: 70738 , date: 30.07.2015]]

List1UniqueIdMap:  
{
101=2012-03-12T00:00:00.000+01:00,
70738=2016-01-26T00:00:00.000+01:00,     
68691=2015-05-01T00:00:00.000+02:00,       
15=2012-06-29T00:00:00.000+02:00}

List2UniqueIdMap:  
{
101=2012-03-12T00:00:00.000+01:00,
70738=2015-07-30T00:00:00.000+02:00,     
68691=2015-02-12T00:00:00.000+01:00,     
15=2012-06-29T00:00:00.000+02:00}

Result:  
[101, 68691, 70738]

共有1个答案

羊舌和安
2023-03-14

首先,您需要从列表2创建一个中间的映射 ,其中每个条目的id都映射到最大日期。这样,我们只需将list1中的每个id与这个最大日期进行比较,看看它是否在之后。

为了考虑您的更新,您还需要保留list1的计数比list2高的id,我们还需要创建另外两个map ,用于存储list1list2的每个id的计数

创建这个映射可以通过list2与条目的ID进行分组来完成。我们使用groupingby(classifier,downlow),分类器是返回条目id的方法-referenceentry::getid。下游收集器用于将具有相同id的所有值收集到一个结果中;在本例中,我们使用Maxby收集器,该收集器将每个条目的日期与barching(keyExtractor)进行比较。因为这个比较器返回一个可选的(为了处理需要收集注释的情况,所以没有最大值),所以它被包装成collecting,然后应用一个完成器操作,在本例中,该操作获取可选值并从中检索日期。count映射的思想是相同的,不同的是,这一次,下游收集器是counting(),它计算具有相同键的值的数量。

Map<Integer, DateTime> map =
    list2.stream()
         .collect(groupingBy(
             Entry::getId,
             collectingAndThen(maxBy(comparing(Entry::getDate)), e -> e.get().getDate())
         ));

Map<Integer, Long> mapCount2 = list2.stream().collect(groupingBy(Entry::getId, counting()));
Map<Integer, Long> mapCount1 = list1.stream().collect(groupingBy(Entry::getId, counting()));

有了这个中间映射,我们就可以很容易地过滤list1:我们只保留映射中不包含当前id的元素,或者如果包含,则当前条目的日期在映射中存储的日期之后。由于我们对重复项不感兴趣,因此将其收集到中。

Set<Integer> ids =
    list1.stream()
         .filter(e -> !mapDate.containsKey(e.getId()) || 
                      e.getDate().isAfter(mapDate.get(e.getId())) ||
                      mapCount1.get(e.getId()) > mapCount2.get(e.getId()))
         .map(Entry::getId)
         .collect(toSet());

用于使代码更干净的静态导入:

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.maxBy;
import static java.util.stream.Collectors.toSet;
 类似资料:
  • 我想用Lambda对列表排序: 但我得到了这个编译错误:

  • 是否可以在没有外部foreach的情况下迭代B。需要使用Java8在2个arays中标识公共值

  • 假设我有一个双人课 我希望对它进行排序,首先是第一个值,然后是第二个值。现在,如果我这样做 一切都很好,列表按对的第一个值排序,但如果我这样做 它因错误而失败 好吧,所以它可能无法推断参数,所以如果我这样做 它因错误而失败 为什么它适用于comparing()而不适用于comparing()。然后比较()?

  • 我有一个包含一些字符串值的列表。我想与另一个字符串进行比较来迭代列表。只有当另一个字符串与列表中的任何元素都不匹配时,那么我才应该进入循环。我试过下面这样的东西,但没有效果。在Java8中有没有其他替代方法可以实现同样的功能? 注意:在循环中,我将向同一列表中添加更多的元素。因此,为了避免,我使用if条件进行验证。

  • 我必须比较两个list(清单1到清单2)上的元素,当这些元素与code属性的元素匹配时,我必须替换为tobereplace属性的值。 在清单1中,我有 在清单2中,我有: 理想情况下,List1应该具有list2的值;我们如何使用Java8流来实现这一点

  • 问题内容: 我需要比较2个不同数据库中的数据库表,以了解差异所在,是否有一个简单的工具或脚本来实现? 问题答案: redgate SQL数据比较