Home > Blockchain >  Time Converter: split content time with ads time
Time Converter: split content time with ads time

Time:04-15

I'm sorry I have a trying to find & fix a math problem

Let's say I have 2 List or array

Content Array

0-50 = C1
50-100 = C2

AD Array

10-20 = A1
30-60 = A2
80-140 = A3

OutPut Should be Like this

0-10 = C1
10-20 = A1
20-30 = C1
30-60 = A2
60-80 = C2
80-100 = A3

Here ads are replacing actual content and splitting the content into a new array of items.

const content  = [
  {start: 0, end: 50, id: 'C1'},
  {start: 50, end: 100, id: 'C2'},
]

const ad = [
  {start:10, end: 20, id: 'A1' },
  {start:30, end: 60, id: 'A2' },
  {start:80, end: 140, id: 'A3' },
]

const newList = []
content.forEach(content => {
  ad.forEach((ad, index) => {
    //0 > 0 && 20 < 50
    if(content.start < ad.start && content.end > ad.end){
        newList.push({start: content.start, end: ad.start, id: content.id})
        newList.push(ad)
   }else{
        console.log(decodeURIComponent(`${content.start} > ${ad.start} && ${content.end} < ${ad.end}`))
    }
  })
})

console.log('newList',newList)

Please Help

CodePudding user response:

This may be a "not so elegant" solution to achieve the desired objective.

Code Snippet

// manipulate timeline to find "gaps" and place "ads"
// recursive method controlled by "idx"
const splitTimeline = (arr, advArr, idx) => {
  const res = [...arr];       // shallow-copy intermediate result array
  const ad = advArr[idx];     // direct access to current iteration of "ad"
  arr.forEach(
    ({ start, end, id }, rIdx) => {     // de-structure and res-array-index
      if (                      // place "ad" in existing "gap"
        start < ad.start &&
        end >= ad.end &&
        id === 'gap'
      ) {
        res.splice(rIdx, 1, { start, end: ad.start, id: 'gap'});
        res.splice(rIdx   1, 0, {
          start: ad.start, end: Math.min(end, ad.end), id: ad.id
        });
        if (end > ad.end) res.splice(rIdx   2, 0, {
          start: ad.end, end, id: 'gap'
        });
      } else if (             // handle edge-case (last "ad" exceeds timeline
        idx === advArr.length - 1 && id === 'gap' &&
        ad.start > start && ad.start < end
      ) {
        res.splice(rIdx, 1, {
          start: ad.start, end: end, id: ad.id
        });
        res.splice(rIdx, 0, {
          start: start, end: ad.start, id: 'gap'
        });
      }
    }
  );
  // recurse if all "ads" not yet processed
  if (idx < advArr.length - 1) return splitTimeline(res, advArr, idx   1);
  else return res;
};

// method to fill "gaps" with "content" (c-array - content-array)
const addContent = (tl, carr) => (    // "tl" is current timeline
  tl.map(({ start, end, id }) => {    // iterate over "tl"
    // if "ad", simply return it as-is
    if (id !== 'gap') return {start, end, id};
    // otherwise, find a matching "content" id for existing "gap"
    return {start, end, id: carr.find(
      ob => start >= ob.start && end <= ob.end
    )?.id ?? "no content"}          // optional chain "id" or return "no content"
  })
);

// simple method to construct, update a timeline
// and place contents and ads within the timeline
const placeAds = (cn, ad) => {
  const cBgn = Math.min(...cn.map(({ start }) => start));
  const cEnd = Math.max(...cn.map(({ end }) => end));
  const initialTimeline = [{
    start: cBgn, end: cEnd, id: 'gap'
  }];
  return (
    addContent(         // method to add "content"
      splitTimeline(    // method to split timelines and place "ads" and "gaps"
        initialTimeline,
        ad,             // the ad array
        0               // initial ad array index set to 0 (for recursion)
      ),
      cn                // the content array
    )
  );
};

const content  = [
  {start: 0, end: 50, id: 'C1'},
  {start: 50, end: 100, id: 'C2'},
];

const ad = [
  {start:10, end: 20, id: 'A1' },
  {start:30, end: 60, id: 'A2' },
  {start:80, end: 140, id: 'A3' },
];

console.log(placeAds(content, ad));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Explanation

Inline comments describe the significant aspects of the solution

CodePudding user response:

Actually, I don't know what I can say about the code, just try this approach:

const content  = [{start: 0, end: 50, id: 'C1'},{start: 50, end: 100, id: 'C2'}];

const ad = [{start:10, end: 20, id: 'A1' },{start:30, end: 60, id: 'A2' },{start:80, end: 140, id: 'A3' }];

const cPoints = content.flatMap(e => [e.start, e.end]); // [0, 50, 50, 100]
const aPoints = ad.flatMap(e => [e.start, e.end]); // [10, 20, 30, 60, 80, 140]
const rangeMin = Math.min(...cPoints); // 0
const rangeMax = Math.max(...cPoints); // 100

const rangePoints = [...new Set([...aPoints, ...cPoints])] // [10, 20, 30, 60, 80, 140, 0, 50, 100]
    .filter(point => (point >= rangeMin) && (point <= rangeMax)) // [10, 20, 30, 60, 80, 0, 50, 100]
    .sort((a, b) => a - b);  // [0, 10, 20, 30, 50, 60, 80, 100]
  
const getObjByPoint = (point, arr) => 
    arr.find((e) => (e.start <= point) && (point <= e.end));

const getFirstId = (point) => 
    (getObjByPoint(point, ad) || getObjByPoint(point, content)).id;
  
const result = rangePoints.reduce((acc, end, index, arr) => {
    if (index === 0) return acc;
    
    let start = arr[index - 1];
    const middle = (start   end) / 2;
    const id = getFirstId(middle);
    if (acc.at(-1)?.id === id) {
        start = acc.pop().start;
    }
    acc.push({ start, end, id });
    
    return acc;
}, []);

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

  • Related