Convert Time: segment time devoted to the main content from the time dedicated to advertisements

Can anyone assist me with solving a math problem?

Let's consider two lists or arrays:

Content Array

0-50 = C1
50-100 = C2

AD Array

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

The desired output should be:

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

In this scenario, the ads are replacing actual content and dividing 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) => {
    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)

Seeking assistance on this problem. Please help!

Answer №1

I'm not entirely sure how to address the code, but maybe you could consider this approach:

const data = [{start: 0, end: 50, id: 'C1'},{start: 50, end: 100, id: 'C2'}];
const adData = [{start:10, end: 20, id: 'A1' },{start:30, end: 60, id: 'A2' },{start:80, end: 140, id: 'A3' }];

const points = data.flatMap(e => [e.start, e.end]); 
const aPoints = adData.flatMap(e => [e.start, e.end]); 
const minRange = Math.min(...points); 
const maxRange = Math.max(...points); 
const range = [...new Set([...aPoints, ...points])]
    .filter(point => (point >= minRange) && (point <= maxRange)) 
    .sort((a, b) => a - b); 
  
const findObjByPoint = (point, arr) => 
    arr.find((e) => (e.start <= point) && (point <= e.end));

const findFirstId = (point) => 
    (findObjByPoint(point, adData) || findObjByPoint(point, data)).id;
  
const output = range.reduce((acc, end, index, arr) => {
    if (index === 0) return acc;
    
    let start = arr[index - 1];
    const middle = (start + end) / 2;
    const id = findFirstId(middle);
    if (acc.at(-1)?.id === id) {
        start = acc.pop().start;
    }
    acc.push({ start, end, id });
    
    return acc;
}, []);

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

Answer №2

While not the most elegant approach, this solution effectively meets the desired goal.

Code Snippet

// With an iterative method controlled by "idx", we manipulate the timeline to identify "gaps" and insert "ads"
const splitTimeline = (arr, advArr, idx) => {
  const res = [...arr];       // Create a shallow copy of the intermediate result array
  const ad = advArr[idx];     // Direct access to the current iteration of "ad"
  arr.forEach(
    ({ start, end, id }, rIdx) => {     // De-structure and get the indexed element in the result array
      if (                      // Insert "ad" into 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 where 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" have not been processed yet
  if (idx < advArr.length - 1) return splitTimeline(res, advArr, idx + 1);
  else return res;
};

// A method to fill "gaps" with "content" from the content-array ("carr")
const addContent = (tl, carr) => (    // "tl" represents the current timeline
  tl.map(({ start, end, id }) => {    // Iterate over the elements in the timeline
    // If it's an "ad", simply return it as-is
    if (id !== 'gap') return {start, end, id};
    // Find a matching "content" id for the existing "gap"
    return {start, end, id: carr.find(
      ob => start >= ob.start && end <= ob.end
    )?.id ?? "no content"}          
  })
);

// A simple method to construct, update a timeline, and place contents and ads within it
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(         
      splitTimeline(    
        initialTimeline,
        ad,             
        0               
      ),
      cn                
    )
  );
};

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

The inline comments detail the key aspects of this solution.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Running 'npm run build' in Vuejs seems to have a mind of its own, acting

Recently, I completed a project and uploaded it to Github. The issue arises when I attempt to clone it to my live server - only about 1 out of 10 times does everything function correctly after running npm run build. My setup consists of Ubuntu 16 with ngin ...

What is the best way to display the first element from a JSON Array in ReactJs?

Looking at the JSON Array data below, how can I print out Charlie? [ [ { "ID": 1, "Name" :"David" },{ "ID": 2, "Name" :"Antony" }],[{ "ID": 1, "Name" :"Bob" },{ "ID": 2, "Name" :"Charlie" } ] ] ...

an occurrence of an element being rendered invisible, within an instance of an element being rendered as flexible,

I am trying to create a button that will show a list of elements. Within this list, there is another button that can be used to either close the list or hide it entirely. However, for some reason, my code is not functioning properly. let btn1 = documen ...

The element 'stripe-pricing-table' is not a recognized property of the 'JSX.IntrinsicElements' type

I am currently trying to incorporate a pricing table using information from the Stripe documentation found at this link. However, during the process, I encountered an issue stating: "Property 'stripe-pricing-table' does not exist on type &ap ...

Having trouble with v-model not updating the data value on a dropdown in Vue.js?

When I set the initial value on the data property, the dropdown option is correctly displayed. However, if I select a different value from the dropdown, the data property does not update accordingly. <select class="form-control" ...

Ways to automatically refresh a page in Javascript after a short period of user inactivity

Similar Question: How Can I Modify This Code To Redirect Only When There Is No Mouse Movement I am looking to update a web page automatically if the user is inactive, specifically through key presses or mouse clicks using Javascript. ...

Error: Invalid character encountered during login script JSON parsing

I found this script online and have been experimenting with it. However, I encountered the following error: SyntaxError: JSON.parse: unexpected character [Break On This Error] var res = JSON.parse(result); The problem lies in the file below as I am unf ...

Which is more efficient for rendering performance: using images, CSS gradients, or box shadows with borders?

I'm curious about improving website scroll and animation performance. Which option would be better for your mobile webapp or website: Using a repeating thin image or CSS3 gradient? or Utilizing a repeating image instead of box shadow with a borde ...

Why is Mongoose returning null when using findOne?

Here is a sample request: interface IGetFullnameRequest extends IAuthenticatedRequest { readonly body: Readonly<{ fullname: string; }>; } This is the controller function to get the fullname: const getFullname = async (req: IGetFullna ...

Troubleshooting a Custom Menu Control in HTML

Would you mind taking a look at the menu I have set up in this fiddle: http://jsfiddle.net/Gk_999/mtfhptwo/3 (function ($) { $.fn.menumaker = function (options) { var cssmenu = $(this), settings = $.extend({ title: "Menu", ...

Issue with Material UI scrollable tabs failing to render properly in Internet Explorer

Currently, we are integrating Material UI into our tab control for our React Web UI. Everything is functioning smoothly in Chrome, but when we attempted to test it in IE, the page failed to load and presented the error below: Unhandled promise rejection ...

What are the steps to showcase a multiplication chart based on user-inputted rows and columns using jQuery?

I'm currently facing some challenges with coding a multiplication table using jQuery. I already have the code to display the multiplication table based on inputted rows, but I need help in modifying it to allow for inputting both rows and columns. An ...

Using Node.js to retrieve child processes associated with a daemon and terminate them

I am attempting to create a node application that allows me to send the command kill -9 to all child processes of a single daemon. Just to clarify, there is one daemon running on our server. Upon startup, it initiates a process for communicating with clie ...

Accessing the index in an Angular ngFor loop allows for

Is there a way to access the index within ngFor in Angular? Check out this link for more information. Appreciate any help! Thank you. ...

How do RxJS collection keys compare?

Is there a more efficient way to compare two arrays in RxJS? Let's say we have two separate arrays of objects. For example: A1: [{ name: 'Sue', age: 25 }, { name: 'Joe', age: 30 }, { name: 'Frank', age: 25 }, { name: & ...

I would appreciate your assistance with the hide button

Is there a way to hide a button after clicking on it? I would greatly appreciate your help! ...

Add a CSS class to an innerHTML element just a single time

I currently have 2 files available: data.php page.php The data.php file is responsible for fetching a row from a SQL database and sending it to the page.php file. Within the page.php file, there is a JavaScript script that receives this row through AJAX ...

How can you eliminate the prop that is injected by a Higher Order Component (HOC) from the interface of the component it produces

In my attempt to create a Higher Order Component, I am working on injecting a function from the current context into a prop in the wrapped component while still maintaining the interfaces of Props. Here is how I wrap it: interface Props extends AsyncReque ...

Developing dynamic objects for input string fields in AngularJS

In my AngularJS view, I have the following setup: <label class="control-label">Name:</label> <input type="text" class="form-control" ng-model="config.name" /> <br /> <label class="control-label">versionSpecificApiConfig:&l ...

What is the best way to combine HTML and JavaScript code within a single JavaScript file?

Is there a way to include a responsive iframe without any scroll in multiple websites by using just one line of code? I found this snippet that seems promising: <script src="testfile.js"></script> The testfile.js contains the necessary HTML a ...