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
…JavaScript113131function splitOpeningHoursEntry(entry) {
2// e.g.: 'Mon : 9:00AM - 7:00PM'
3const indexOfColon = entry.indexOf(':'); // e.g. 5
4
5// entry.substring(0, 5) ... e.g.: 'Mon '
6const day = entry.substring(0, indexOfColon);
7// entry.substring(6) ... e.g.: ' 9:00AM - 7:00PM'
8const hours = entry.substring(indexOfColon + 1);
9
10// e.g.: ['Mon', '9:00AM - 7:00PM']
11return [day.trim(), hours.trim()];
12}
13
… or it can be done by
split
-ting with a Regular Expression like … /(^[^:s]+)s*:s*/ … andslice
-ing the results array …JavaScript113131function regexSplitOpeningHoursEntry(entry) {
2// [https://regex101.com/r/vGRck7/3]
3// entry.split(':') // ["Mon ", " 9", "00AM - 7", "00PM"]
4
5// [https://regex101.com/r/vGRck7/2]
6// entry.split(/s*:s*/) // ["Mon", "9", "00AM - 7", "00PM"]
7
8// [https://regex101.com/r/vGRck7/1]
9// entry.split(/(^[^:s]+)s*:s*/) // ["", "Mon", "9:00AM - 7:00PM"];
10
11return entry.split(/(^[^:s]+)s*:s*/).slice(1);
12}
13
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 …JavaScript121sampleList.map(splitOpeningHoursEntry);
2
… or like that …
JavaScript121sampleList.map(regexSplitOpeningHoursEntry);
2
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; }