java - Java8: Filter and compare 2 Lists with Lambda -
the task:
i have 2 lists contains of entrys (id + datetime) id's can multiple differen datetimes.
i need list of id's whith following conditions:
- the id of list1 not in list2
- if id of list1 in list2, see if has higher date
- if id of list1 has higher count in list2
the question: how can java 8 streams?
examplecode:
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: list of id's list1 have higher date or doesnt exists in list2 // filter list1 every id unique (with highest date) final map<integer, datetime> list1uniqueidmap = new hashmap<integer, datetime>(); (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 every id unique (with highest date) final map<integer, datetime> list2uniqueidmap = new hashmap<integer, datetime>(); (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); // list of id's in list1 not in list2, or, if in list2, if have higher date // furthermore, the id's of list1 have higher count in list2 final set<integer> resultset = new hashset<integer>(); (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; (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() + "]"; } } }
output of example:
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]
first, want create intermediate map<integer, datetime>
list2
each entry's id mapped maximum date. way, have compare each id list1
maximum date see if after or not.
to consider update need keep ids have higher count of list1
in list2
, need create 2 map<integer, long>
stores count each id list1
, list2
creating map can done grouping list2
entry's id. using groupingby(classifier, downstream)
classifier being method-reference entry::getid
returning id of entry. downstream collector used collect value having same id single result; in case, using maxby
collector comparing each entry's date comparing(keyextractor)
. since comparator returns optional
(to handle case have noting collect, no maximum value), wrapped collectingandthen
applies finisher operation which, in case, gets optional value , retrieve date it. idea same count map, difference time, downstream collector counting()
counts number of values having same key.
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()));
having intermediate map, can filter list1
: keep elements map not contain current id, or if does, current entry's date after 1 stored in map. since we're not interested in duplicates, collected set
.
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());
static imports used make code cleaner:
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;
Comments
Post a Comment