0

Java : I have a list of String which holds Date column data from database. I want the count of each month .

Say I have data : 2021-07-01 2021-08-20 2021-08-25 2021-09-05 2022-01-06 2022-06-07

I want to retrieve value 1 for July,2 for August, 1 for September, 1 for January, 1 for June .

How can I use stream API to achieve this? Or any other method to retrieve vthis data

Suprita
  • 11
  • 2
    Does this answer your question? [Combine array of dates and sum values per month in Java](https://stackoverflow.com/questions/32480926/combine-array-of-dates-and-sum-values-per-month-in-java) – PM 77-1 Aug 04 '22 at 14:39
  • @PM77-1 [That question](https://stackoverflow.com/q/32480926/642706) is quite similar. But this Question here wants only a count of each month’s occurrence count, woh no extraneous number to sum. So I think this Question deserves its own solution. – Basil Bourque Aug 04 '22 at 14:45

2 Answers2

2

tl;dr

List
.of( "2021-07-01", "2021-08-20", "2021-08-25", "2021-09-05", "2022-01-06", "2022-06-07" )
.stream()
.map( input -> LocalDate.parse( input ) )      // Parse each element as a `LocalDate` object, for a new stream.
.collect(
    Collectors.groupingBy( date -> 
                   YearMonth :: from ,         // Extract a `YearMonth` from each `LocalDate` as the key.
                   Collectors.counting()       // Count occurrences.
    )
)                                              // Return a `Map`.

Details

Make example data.

List< String > inputs = List.of( "2021-07-01", "2021-08-20", "2021-08-25", "2021-09-05", "2022-01-06", "2022-06-07" );

Make a stream of those inputs. Parse each element as a LocalDate object, for a new stream. Produce a key-value Map < YearMonth , Integer > object by extracting a YearMonth from each LocalDate as the key, and summing one as a count of occurrences for the value.

Map< YearMonth , Integer > monthCounts = 
    inputs
        .stream()
        .map( input -> LocalDate.parse( input ) )      // Parse each element as a `LocalDate` object, for a new stream.
        .collect(
            Collectors.groupingBy( date -> 
                           YearMonth :: from  ,        // Extract a `YearMonth` from each `LocalDate` as the key.
                           Collectors.counting()       // Count occurrences.
            )
        )                                              // Return a `Map`.
;

See this code run live at Ideone.com.

{2021-09=1, 2021-08=2, 2021-07=1, 2022-06=1, 2022-01=1}

Sort by year-month: NavigableMap

You might want to keep the entries in your resulting map sorted by the YearMonth keys. If so:

  • Change your declared map type from Map to NavigableMap interface.
  • Add an argument for TreeMap :: new to instantiate an objecting implementing NavigableMap.
NavigableMap < YearMonth, Long > monthCounts =
        inputs
                .stream()
                .map( input -> LocalDate.parse( input ) )
                .collect(
                        Collectors.groupingBy(
                                YearMonth :: from ,
                                TreeMap::new,
                                Collectors.counting()
                        )
                );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

I wrote up a process to allow you to get your desired goal using Streams and Lambdas.

  1. Parse your dates into an Array of LocalDates.

  2. Define a Predicate for your criteria.

  3. Filter your Stream using your Predicate and get the count().

     String[] dates = { "2021-07-01", "2021-08-20", "2021-08-25", "2021-09-05", "2022-01-06", "2022-06-07" };
     LocalDate[] localDates = new LocalDate[dates.length];
    
     for(int i = 0; i < dates.length; i++){
         localDates[i] = LocalDate.parse(dates[i]);
     }
    
     Predicate<LocalDate> month = localDate -> localDate.getMonth().equals(Month.AUGUST);
    
     long count = Arrays.stream(localDates).filter(month).count();