I have an array of string items …
[ 'Mon : 9:00AM - 7:00PM', 'Tue : 9:00AM - 10:00PM', 'Wed : Closed', 'Thu : 9:00AM - 7:00PM', 'Fri : 9:00AM - 7:00PM', 'Sat : Closed', 'Sun : Closed', ]
… and I want to achieve a result like the one below …
[ 'Mon: 9:00AM - 7:00PM', 'Tue: 9:00AM - 10:00PM', 'Wed: Closed', 'Thu-Fri: 9:00AM - 7:00PM', 'Sat-Sun: Closed', ]
Any help is really appreciated.
Advertisement
Answer
Firstly one needs to separate the
day
value from thehours
value part of a single opening hours string.This either can be achieved via
indexOf
,substring
andtrim
…function splitOpeningHoursEntry(entry) { // e.g.: 'Mon : 9:00AM - 7:00PM' const indexOfColon = entry.indexOf(':'); // e.g. 5 // entry.substring(0, 5) ... e.g.: 'Mon ' const day = entry.substring(0, indexOfColon); // entry.substring(6) ... e.g.: ' 9:00AM - 7:00PM' const hours = entry.substring(indexOfColon + 1); // e.g.: ['Mon', '9:00AM - 7:00PM'] return [day.trim(), hours.trim()]; }
… or it can be done by
split
-ting with a Regular Expression like … /(^[^:s]+)s*:s*/ … andslice
-ing the results array …function regexSplitOpeningHoursEntry(entry) { // [https://regex101.com/r/vGRck7/3] // entry.split(':') // ["Mon ", " 9", "00AM - 7", "00PM"] // [https://regex101.com/r/vGRck7/2] // entry.split(/s*:s*/) // ["Mon", "9", "00AM - 7", "00PM"] // [https://regex101.com/r/vGRck7/1] // entry.split(/(^[^:s]+)s*:s*/) // ["", "Mon", "9:00AM - 7:00PM"]; return entry.split(/(^[^:s]+)s*:s*/).slice(1); }
Then one has to
map
an entire array of opening hours strings into an array of arrays, where each array-item contains theday
value as first and thehours
value as second array item … either like this …sampleList.map(splitOpeningHoursEntry);
… or like that …
sampleList.map(regexSplitOpeningHoursEntry);
On top one needs to
reduce
this array of splitted[<day>, <hours>]
entries into its compact form …Finally one has to
map
each splitted[<day>, <hours>]
entry with a concatenation task back into its human readable string form….
const sampleList = [ 'Mon : 9:00AM - 7:00PM', 'Tue : 9:00AM - 10:00PM', 'Wed : Closed', 'Thu : 9:00AM - 7:00PM', 'Fri : 9:00AM - 7:00PM', 'Sat : Closed', 'Sun : Closed', ]; function splitOpeningHoursEntry(entry) { // e.g.: 'Mon : 9:00AM - 7:00PM' const indexOfColon = entry.indexOf(':'); // e.g. 5 // entry.substring(0, 5) ... e.g.: 'Mon ' const day = entry.substring(0, indexOfColon); // entry.substring(6) ... e.g.: ' 9:00AM - 7:00PM' const hours = entry.substring(indexOfColon + 1); // e.g.: ['Mon', '9:00AM - 7:00PM'] return [day.trim(), hours.trim()]; } function regexSplitOpeningHoursEntry(entry) { // [https://regex101.com/r/vGRck7/3] // entry.split(':') // ["Mon ", " 9", "00AM - 7", "00PM"] // [https://regex101.com/r/vGRck7/2] // entry.split(/s*:s*/) // ["Mon", "9", "00AM - 7", "00PM"] // [https://regex101.com/r/vGRck7/1] // entry.split(/(^[^:s]+)s*:s*/) // ["", "Mon", "9:00AM - 7:00PM"]; return entry.split(/(^[^:s]+)s*:s*/).slice(1); } function compactOpeningHoursEntries(compactEntries, splitEntry, idx, arr) { // get the predecessor item of the currently // processed `splitEntry` item or default to []. const prevSplitEntry = arr[idx - 1] || []; // get the successor item of the currently // processed `splitEntry` item or default to []. const nextSplitEntry = arr[idx + 1] || []; if (prevSplitEntry[1] !== splitEntry[1]) { // in case the previous and current `hours` values do not match ... // ... push the current entry of splitted `day` and `hours` // values into `compactEntries` which is the accumulating // array of the compacted form of all opening hours entries. compactEntries.push(splitEntry); } else if (nextSplitEntry[1] !== splitEntry[1]) { // ... or in case the next and current `hours` values do not match ... const lastCompactEntry = compactEntries[compactEntries.length - 1]; // ...retrieve the first and the last day value // of a compactly written day-range format... const firstDayInRange = lastCompactEntry[0]; const lastDayInRange = splitEntry[0]; // ...and create and rewrite its compact form // as the compacted entry's final day value. lastCompactEntry[0] = firstDayInRange + '-' + lastDayInRange; } return compactEntries; } function concatOpeningHoursEntry([day, hours]) { return `${ day }: ${ hours }`; } // First one needs to separate the `day` from the // `hours` part of a single opening hours string console.log( "splitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ...", splitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ); console.log( "regexSplitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ...", regexSplitOpeningHoursEntry('Mon : 9:00AM - 7:00PM') ); // Then one does map an entire array of opening hours strings // into an array of arrays, where each array item contains the // `day` value as first and the `hours` value as second array item. console.log( '... list item `split` mapping ... ', sampleList .map(splitOpeningHoursEntry) //.map(regexSplitOpeningHoursEntry) ) // On top one has to `reduce` this array of splitted // `[<day>, <hours>]` entries into its compact form. console.log( '... list item `split` mapping and split entry reducing ... ', sampleList .map(splitOpeningHoursEntry) .reduce(compactOpeningHoursEntries, []) ); // Finally one needs to `map` each splitted `[<day>, <hours>]` entry // with a concatenation task back into its human readable string form. console.log( '... list item `split` mapping, reducing and a final concatenation mapping ... ', sampleList .map(splitOpeningHoursEntry) .reduce(compactOpeningHoursEntries, []) .map(concatOpeningHoursEntry) );
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another less talkative proof of concept …
function splitOpeningHoursEntry(entry) { return entry.split(/(^[^:s]+)s*:s*/).slice(1); } function concatOpeningHoursEntry([day, hours]) { return `${ day }: ${ hours }`; } function compactOpeningHoursEntries(compactEntries, splitEntry, idx, arr) { const prevSplitEntry = arr[idx - 1] || []; const nextSplitEntry = arr[idx + 1] || []; if (prevSplitEntry[1] !== splitEntry[1]) { compactEntries.push(splitEntry); } else if (nextSplitEntry[1] !== splitEntry[1]) { const lastCompactEntry = compactEntries[compactEntries.length - 1]; const firstDayInRange = lastCompactEntry[0]; const lastDayInRange = splitEntry[0]; lastCompactEntry[0] = firstDayInRange + '-' + lastDayInRange; } return compactEntries; } console.log([ 'Mon : 08:00AM - 17:00PM', 'Tue : 08:00AM - 17:00PM', 'Wed : 08:00AM - 17:00PM', 'Thu : 10:00AM - 14:00PM', 'Fri : 10:00AM - 14:00PM', 'Sat : Closed', 'Sun : Closed', ], '=>', [ 'Mon : 08:00AM - 17:00PM', 'Tue : 08:00AM - 17:00PM', 'Wed : 08:00AM - 17:00PM', 'Thu : 10:00AM - 14:00PM', 'Fri : 10:00AM - 14:00PM', 'Sat : Closed', 'Sun : Closed', ] .map(splitOpeningHoursEntry) .reduce(compactOpeningHoursEntries, []) .map(concatOpeningHoursEntry) );
.as-console-wrapper { min-height: 100%!important; top: 0; }