How could I compute a list of "open hours" in javascript from a list of start and end times with overlaps?

huangapple go评论81阅读模式
英文:

How could I compute a list of "open hours" in javascript from a list of start and end times with overlaps?

问题

const 周一营业时间 = [
  { 开始: "09:00", 结束: "14:00" },
  { 开始: "10:00", 结束: "15:00" },
  { 开始: "17:00", 结束: "23:00" },
];

const 计算后的周一营业时间 = [
  { 开始: "09:00", 结束: "15:00" },
  { 开始: "17:00", 结束: "23:00" },
];
英文:

I am trying to simplify a list of open times so that there are no overlaps/duplicate information showing (in javascript).

Here is an example of what I am trying to achieve:

The starting array would look something like this:

const mondayHours = [
  { start: "09:00", end: "14:00" },
  { start: "10:00", end: "15:00" },
  { start: "17:00", end: "23:00" },
];

And the data is currently displayed like:
Open: 9am-2pm, 10am-3pm, 5pm-11pm

I want the result to return an array for the total open hours like so:

const computedMondayHours = [
  { start: "09:00", end: "15:00" },
  { start: "17:00", end: "23:00" },
];

And so that the data will be displayed like:
>Open: 9am-3pm, 5pm-11pm

I have found a solution online that returns the latest open times with the earliest close times, thinking I could convert it for my uses, but that has not worked at all:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const hours = [{
    start: &quot;09:00&quot;,
    end: &quot;14:00&quot;
  },
  {
    start: &quot;10:00&quot;,
    end: &quot;15:00&quot;
  },
  {
    start: &quot;17:00&quot;,
    end: &quot;23:00&quot;
  }
]

const isBetween = (value, start, end) =&gt; value &gt; start &amp;&amp; value &lt; end
const computeOpenHours = (dayHours) =&gt; {
  const index = {}
  dayHours.forEach(({
    start: aStart,
    end: aEnd
  }) =&gt; {
    dayHours.forEach(({
      start: bStart,
      end: bEnd
    }) =&gt; {
      aStart = isBetween(bStart, aStart, aEnd) &amp;&amp; bStart &gt; aStart ? bStart : aStart
      aEnd = isBetween(bEnd, aStart, aEnd) &amp;&amp; bEnd &lt; aEnd ? bEnd : aEnd
    })
    const key = `${aStart}-${aEnd}`
    const value = {
      start: aStart,
      end: aEnd
    }
    index[key] = index[key] || value
  })
  return Object.keys(index).map(k =&gt; index[k])
}

console.log(computeOpenHours(hours))

<!-- end snippet -->

答案1

得分: 1

你可以减少时间并检查当前开始时间是否大于前一个结束时间。

注意: 这个简单的算法假设输入数组已经排序。

const calcTimeSlots = (workingHours) =>
  workingHours.reduce((acc, { start, end }) => {
    if (acc.length === 0) {
      acc.push({ start, end });
    } else {
      const latest = acc[acc.length - 1];
      if (parseTimeAsMillis(start) > parseTimeAsMillis(latest.end)) {
        acc.push({ start, end });
      } else if (parseTimeAsMillis(end) > parseTimeAsMillis(latest.end)) {
        latest.end = end;
      }
    }
    return acc;
  }, []);
  
const parseTimeAsMillis = (str) =>
  str.split(':')
  .map((t, i, a) => parseInt(t) * 60 * (a.length - 1))
  .reduce((total, curr) => total + curr);
  
const mondayHours = [
  { start: '09:00', end: '14:00' },
  { start: '10:00', end: '15:00' },
  { start: '17:00', end: '23:00' }
];

const tuesdayHours = [
  { start: '09:00', end: '14:00' },
  { start: '10:00', end: '11:00' }
];

console.log(calcTimeSlots(mondayHours));
console.log(calcTimeSlots(tuesdayHours));
英文:

You can reduce the hours and check if the current start is greater than the prev end time.

Note: This naïve algorithm assumes the input array is already sorted.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const calcTimeSlots = (workingHours) =&gt;
  workingHours.reduce((acc, { start, end }) =&gt; {
    if (acc.length === 0) {
      acc.push({ start, end });
    } else {
      const latest = acc[acc.length - 1];
      if (parseTimeAsMillis(start) &gt; parseTimeAsMillis(latest.end)) {
        acc.push({ start, end });
      } else if (parseTimeAsMillis(end) &gt; parseTimeAsMillis(latest.end)) {
        latest.end = end;
      }
    }
    return acc;
  }, []);
  
const parseTimeAsMillis = (str) =&gt;
  str.split(&#39;:&#39;)
  .map((t, i, a) =&gt; parseInt(t) * 60 * (a.length - 1))
  .reduce((total, curr) =&gt; total + curr);
  
const mondayHours = [
  { start: &#39;09:00&#39;, end: &#39;14:00&#39; },
  { start: &#39;10:00&#39;, end: &#39;15:00&#39; },
  { start: &#39;17:00&#39;, end: &#39;23:00&#39; }
];

const tuesdayHours = [
  { start: &#39;09:00&#39;, end: &#39;14:00&#39; },
  { start: &#39;10:00&#39;, end: &#39;11:00&#39; }
];

console.log(calcTimeSlots(mondayHours));
console.log(calcTimeSlots(tuesdayHours));

<!-- language: lang-css -->

.as-console-wrapper { top: 0; max-height: 100% !important; }

<!-- end snippet -->

Also, here is a related question that I previously answered that may help:

> "Moment.js - Duration within business/open/shift hours?"

答案2

得分: 0

const hours = [
  {"start": "09:00", "end": "14:00"},
  {"start": "10:00", "end": "15:00"},
  {"start": "17:00", "end": "23:00"}
];

// returns -ve if a<b, 0 if a=b, +ve if a>b
function cmp(a, b) {
  return a.replace(':', '') - b.replace(':', '');
}

function mergeIfOverlap({ start: s1, end: e1 }, { start: s2, end: e2 }) {
  return cmp(s1, s2) <= 0 && cmp(e1, s2) >= 0 && { start: s1, end: cmp(e1, e2) >= 0 ? e1 : e2 };
}

const result = [...hours].sort(({ start: a }, { start: b }) => cmp(a, b))
  .reduce((a, c, _, x, y) => (
    x = a.findIndex(i => y = mergeIfOverlap(i, c) || mergeIfOverlap(c, i)),
    y && (a[x] = y) || a.push(c), a), []);

console.log(result);
英文:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const hours = [{&quot;start&quot;:&quot;09:00&quot;,&quot;end&quot;:&quot;14:00&quot;},
               {&quot;start&quot;:&quot;10:00&quot;,&quot;end&quot;:&quot;15:00&quot;},
               {&quot;start&quot;:&quot;17:00&quot;,&quot;end&quot;:&quot;23:00&quot;}]

// returns -ve if a&lt;b, 0 if a=b, +ve if a&gt;b
function cmp(a, b) {
  return a.replace(&#39;:&#39;,&#39;&#39;) - b.replace(&#39;:&#39;,&#39;&#39;)
}
function mergeIfOverlap({start:s1, end:e1}, {start:s2, end:e2}) {
  return cmp(s1,s2)&lt;=0 &amp;&amp; cmp(e1,s2)&gt;=0
    &amp;&amp; {start: s1, end: cmp(e1,e2)&gt;=0 ? e1 : e2}
}

const result = [...hours].sort(({start:a},{start:b})=&gt;cmp(a,b))
  .reduce((a,c,_,x,y)=&gt;(
    x=a.findIndex(i =&gt; y=mergeIfOverlap(i,c)||mergeIfOverlap(c,i)),
    y &amp;&amp; (a[x]=y) || a.push(c), a), [])

console.log(result)

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月18日 03:42:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488617.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定