2
  public class ArrayOfArrayList {
public static void main(String[] args) {
    List<Date> dateList1 = new ArrayList<Date>();
    List<Date> dateList2 = new ArrayList<Date>();
    Calendar cal = new GregorianCalendar();
    for(int i = 0; i < 5; i++) {
        Date d1 = new Date();
        cal.setTime(d1);
        cal.add(Calendar.DATE, i);
        dateList1.add(cal.getTime());
    }
    System.out.println("   *************** Date List 1st ****************");
    for(Date date1 : dateList1) {
        System.out.println("1stList"+date1);
    }
    System.out.println("   *************** Date List 1st ****************");

    for(int i = 2; i < 8; i++) {
        Date d2 = new Date();
        cal.setTime(d2);
        cal.add(Calendar.DATE, i);
        dateList2.add(cal.getTime());
    }
    System.out.println("   *************** Date List 2nd ****************");
    for(Date date2 : dateList2) {
        System.out.println("2ndList"+date2);
    }
    System.out.println("   *************** Date List 2nd ****************");

    System.out.println("   *********** Start Union Dates ************");
    List<Date> finalList = union(dateList1,dateList2);
    Collections.sort(finalList);
    System.out.println("\n   ********* After Union Dates ***********");
    for(Date fDate : finalList) {
        System.out.println(fDate);
    }
    System.out.println("\n ********* After Union Dates **********");    
}

private static  List<Date> union(List<Date> dateList1, List<Date> dateList2)       {
    HashSet<Date> dateSet = new HashSet<Date>();
    dateSet.addAll(dateList1);
    dateSet.addAll(dateList2);
    List<Date> finalDateList = new ArrayList<Date>(dateSet);
    return finalDateList;
}}

with Union Method still i am getting Duplicate Dates could you anyone help me to fix this issue some time answer comes correct but sometime duplicate still present please guide me

O/P

     *************** Date List 1st ****************
    1stListFri Oct 21 00:38:53 IST 2016
    1stListSat Oct 22 00:38:53 IST 2016
    1stListSun Oct 23 00:38:53 IST 2016
    1stListMon Oct 24 00:38:53 IST 2016
    1stListTue Oct 25 00:38:53 IST 2016
    *************** Date List 1st ****************
    *************** Date List 2nd ****************
    2ndListSun Oct 23 00:38:53 IST 2016
    2ndListMon Oct 24 00:38:53 IST 2016
    2ndListTue Oct 25 00:38:53 IST 2016
    2ndListWed Oct 26 00:38:53 IST 2016
    2ndListThu Oct 27 00:38:53 IST 2016
    2ndListFri Oct 28 00:38:53 IST 2016
    *************** Date List 2nd ****************
    *************** Start Union Dates ****************

    *************** After Union Dates ****************
         Fri Oct 21 00:38:53 IST 2016
         Sat Oct 22 00:38:53 IST 2016
         Sun Oct 23 00:38:53 IST 2016
         Sun Oct 23 00:38:53 IST 2016
         Mon Oct 24 00:38:53 IST 2016
         Mon Oct 24 00:38:53 IST 2016
         Tue Oct 25 00:38:53 IST 2016
         Tue Oct 25 00:38:53 IST 2016
         Wed Oct 26 00:38:53 IST 2016
         Thu Oct 27 00:38:53 IST 2016
         Fri Oct 28 00:38:53 IST 2016

   *************** After Union Dates ****************

As you can see the Above Outputs still duplicate is present in the final list after Union of two dates

Sadina Khatun
  • 1,136
  • 2
  • 18
  • 27

3 Answers3

5

Your problem is here; as you do:

dateList1.add(cal.getTime());

You assume that two dates are equal when their printout (like above) is equal. But that is not true! You simply forgot that "dates" include milli seconds, too. If you change your formatting to include that information, you will find that your dates might have same hours:minutes:seconds ... but all different milli second values!

Thus the Set does not see duplicated entries; it just sees all different objects!

So, in order to make your union work, you have to "normalize" those parts within a Date that you want to ignore. Two ways there:

  1. As mentioned in the comments, just push "0" for milliseconds into all the created Date objects!
  2. You could be using a TreeSet and a custom Comparator; and that Comparator can ensue that Dates that are only different on milliseconds are showing up as equal. But that isn't really a great approach, as you have no control which of your Dates will "survive" then.
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    The use of the TreeSet, along with the 0'ing of milliseconds would solve the whole problem, including the sorting into ascending order. Good call @GhostCat – Ashley Frieze Oct 20 '16 at 19:42
2

tl;dr

SortedSet<ZonedDateTime> union = 
    new TreeSet<>().addAll( zdtsA ).addAll( zdtsB ) ;

Details

The accepted Answer by GhostCat is correct. The poorly designed toString method masked the fractional second that made each seemingly-duplicate value actually distinct.

Avoid legacy date-time classes

The old date-time classes such as java.util.Date and java.util.Calendar are poorly designed, confusing, and troublesome. They are now legacy, supplanted by the java.time classes.

Among the many reasons to replace those old classes is the poor choice of behavior of the toString method. Not only does it dynamically apply a time zone to a value that is actually in UTC, it also masks the fractional second. That hiding of the fractional second is your core problem here as you did not realize the values were identical to the second but not identical in the fraction.

java.time

The equivalent of java.util.Date is Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Fortunately, the implementation of the toString methods in the java.time classes such as Instant do not hide the fractional second. By default the fractional second, if any, is displayed in groups of 3 digits as needed for the value. So you will see zero, three, six, or nine digits of fractional second when generating a String to represent the date-time value.

Instant

To convert to/from java.time, look to new methods added on the old classes.

Instant instant = myUtilDate.toInstant();

Truncate

You can truncate the fractional second if desired. You can truncate to any granularity you want, as defined in a TemporalUnit such as those implemented in ChronoUnit such as whole seconds, minutes, hours, etc.

Instant instant = myUtilDate.toInstant().truncatedTo( ChronoUnit.SECONDS );

If you want to increment by 24-hour increments, call the plus method on Instant.

Instant dayLater = instant.plus( 1 , ChronoUnit.DAYS );

ZonedDateTime

If you want to increment by days that respect anomalies such as Daylight Saving Time (DST) rather than simply adding 24-hour increments, apply a time zone (ZoneId) to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

By the way, if you only cared about date and not time-of-day, extract a LocalDate with a call to toLocalDate.

Increment by days, and collect.

int count = 5 ;
List<ZonedDateTime> datesA = new ArraySet<>( count );
for( int i = 1 , i <= count , i++ ) {
    datesA.add( zdt );
    // Prepare for next loop.
    zdt = zdt.plusDays( 1 );
}

SortedSet

A TreeSet is a Set and so eliminates duplicates. A TreeSet is also a SortedSet (see Tutorial) and so keeps the values sorted, in this case sorted in chronological order. To union while eliminating duplicates, add all elements of both List objects to a SortedSet like TreeSet.

SortedSet<ZonedDateTime> union = new TreeSet<>();
union.addAll( datesA );
union.addAll( datesB );

You can make a List from the SortedSet similar to code seen in the Question. The SortedSet iterator traverses the set in ascending element order, so the resulting List will be in chronological order.

List<ZonedDateTime> finalDateList = new ArrayList<>(dateSet);

For more discussion of SortedSet, see this Question, this, and this.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Community
  • 1
  • 1
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
-1

Use set as filter, not as storage:

    HashSet<String> dateSet = new HashSet<String>();
    return Stream.concat(dateList1.stream(), dateList2.stream())
            .filter(d -> dateSet.add(d.toString()))
            .collect(Collectors.toList());
rustot
  • 331
  • 1
  • 11
  • 1
    I've downvoted this because it uses some rather non-intuitive techniques here. It's aggregating to a set anyway, but then using the result of aggregation as a filter - that's a filter with an odd side-effect. I think this code would be hard to understand in real life. You may as well just collect the two lists to a set and then convert that set back to a list. It also doesn't answer the OP's question. – Ashley Frieze Oct 20 '16 at 19:41
  • 1
    I agree with Ashley. Another person might look at this code for an hour, not understanding the point of turning the Date into a String so that "equal" Dates can be filtered out. – GhostCat Oct 20 '16 at 19:44