Home > Back-end >  Rotate elements of a collection of DayOfWeek into locale-defined order
Rotate elements of a collection of DayOfWeek into locale-defined order

Time:10-22

Given we can determine the first day of the week by soft-coding with Locale:

DayOfWeek firstDayOfWeek = WeekFields.of( Locale.US ).getFirstDayOfWeek() ;  // Sunday-Saturday.

… and given that Java comes with a built-in enum defining days of the week, DayOfWeek:

DayOfWeek[] dows = DayOfWeek.values() ;  // Monday-Sunday

How can we create another array or a list of whose elements are the DayOfWeek enum objects rearranged in order defined by our specified locale?

CodePudding user response:

tl;dr

Collections.rotate( 
    new ArrayList<> ( List.of( DayOfWeek.values() ) ) ,   // Actually, you would instantiate elsewhere and pass here.
    DayOfWeek.MONDAY.ordinal() - WeekFields.of( Locale.US ).getFirstDayOfWeek().ordinal()  
)

Details

Fortunately, you need not do the list-rotation work yourself. The Collections utility class offers a rotate method. Pass your list along with an offset.

To quote the Javadoc:

Rotates the elements in the specified list by the specified distance. After calling this method, the element at index i will be the element previously at index (i - distance) mod list.size(), for all values of i between 0 and list.size()-1, inclusive. (This method has no effect on the size of the list.)

For example, suppose list comprises [t, a, n, k, s]. After invoking Collections.rotate(list, 1) (or Collections.rotate(list, -4)), list will comprise [s, t, a, n, k].

final List< DayOfWeek > iso8601 = List.of( DayOfWeek.values() ) ;  // Monday-Sunday, defined in ISO 8601 standard.
List< DayOfWeek > localeOrder = new ArrayList<>( iso8601 ) ;       // Duplicate the list of DayOfWeek objects.
Locale locale = Locale.US ;
DayOfWeek localeFirstDayOfWeek = WeekFields.of( locale ).getFirstDayOfWeek() ;  // Sunday-Saturday.
int distance = DayOfWeek.MONDAY.ordinal() - localeFirstDayOfWeek.ordinal() ;
Collections.rotate( localeOrder , distance ) ;

Dump to console.

System.out.println( iso8601 ) ;
System.out.println( localeOrder ) ;
System.out.println( distance ) ;

See that code run at Ideone.com.

[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]

[SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY]

-6

Or more briefly:

List< DayOfWeek > localeOrder = new ArrayList< DayOfWeek > ( List.of( DayOfWeek.values() ) ) ;   
Collections.rotate( 
    localeOrder , 
    DayOfWeek.MONDAY.ordinal() - WeekFields.of( Locale.US ).getFirstDayOfWeek().ordinal()  
) ;

See this code run at Ideone.com.

[SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY]

CodePudding user response:

Here's how it can be done using List.subList() and Stream.concat().

The core idea

The rotated list can be constructed from two parts:

  • From the first day of the week to Sunday (inclusive);
  • From Monday to the first day of the week (exclusive). In case when the first day of the week is Monday, the second part would be empty.

That's how implementation might look like:

DayOfWeek firstDayOfWeek = WeekFields.of(Locale.US).getFirstDayOfWeek();   // the first Day of Week
    
List<DayOfWeek> initial = new ArrayList<>(EnumSet.allOf(DayOfWeek.class)); // initial list of Days of Week ordered according to ISO-8601
        
List<DayOfWeek> rotated = Stream.concat(
    initial.subList(firstDayOfWeek.ordinal(), DayOfWeek.SUNDAY.ordinal()   1).stream(), // from the firstDayOfWeek to Sunday inclusive
    initial.subList(DayOfWeek.MONDAY.ordinal(), firstDayOfWeek.ordinal()).stream()      // from Monday to the firstDayOfWeek exclusive
).toList();
        
rotated.forEach(System.out::println); // printing the result

Output:

SUNDAY
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY

A link to Online Demo

  • Related