【问题标题】:getting array of unoccupied ranges between two number获取两个数字之间的未占用范围数组
【发布时间】:2021-03-28 09:01:57
【问题描述】:

考虑我有以下数组:

[{Id:'1' , Title: 'Group A' , Start: '100' , End:'200'} , 
 {Id:'2' , Title: 'Group B' , Start: '350' , End:'500'} ,
 {Id:'3' , Title: 'Group C' , Start: '600' , End:'800'} ]

我想获得 100 到 999 之间的未占用范围。 我需要的最终结果是:

[{Start: '201' , End:'349'} , 
 {Start: '501' , End:'599'} ,
 {Start: '801' , End:'999'} ]

【问题讨论】:

  • 数据排序了吗?你有重叠吗?什么不起作用?请添加您的尝试。
  • { Start: '0', End: '99' } 呢?
  • 它们是排序的,没有平均重叠
  • 您使用的是哪个 dbms?你可以在数据库中做到这一点

标签: javascript jquery arrays json


【解决方案1】:

您需要遍历每个数组项并找到上一个未占用的范围并将其插入新数组中。然后在最后一项中,您必须检查最后一项是否占用了所有空间,直到最大值。如果不是,我们还需要添加该范围。 您可以使用Array.reduce 函数执行以下操作,

let sortedArr = [{Id:'1' , Title: 'Group A' , Start: '100' , End:'200'} , 
       {Id:'2' , Title: 'Group B' , Start: '350' , End:'500'} ,
       {Id:'3' , Title: 'Group C' , Start: '600' , End:'800'} ];

const MIN = 100;
const MAX = 999;

let res = sortedArr.reduce((prev, curr, index, arr) => {
  obj = {Start: 0, End: 0};
  
  // checking if the first item has any unoccupied range before it's Start value.
  if(index === 0 && Number(curr.Start) > MIN) {
    obj = {Start: MIN, End: Number(curr.Start) - 1};
    prev.push(obj);
  } else if(index !== 0 && Number(arr[index - 1].End) + 1 < Number(curr.Start)) { 
  // If there is a range between the previous item's End and curr item's Start.
    obj = {Start: Number(arr[index - 1].End) + 1, End: Number(curr.Start) -1};
    prev.push(obj);
  }
  
  // checking if the last item has any range after it's End value.
  if(index === arr.length -1 && Number(curr.End) < MAX) {
    obj = {Start: Number(curr.End) + 1, End: MAX};
    prev.push(obj);
  } else {
    return prev;
  }
  
  return prev;
}, [])

console.log(res);

【讨论】:

    【解决方案2】:

    采用回归基础的方法:从未占用的整个范围开始,循环遍历数据中的每个范围,如果它在输出中现有的未占用范围内开始(相反,第一个总是如此),将其删除在数据范围的开头未占用的范围,并从数据范围的末尾添加一个新的未占用条目到正在被剪切的现有范围的末尾(实际上在代码中更清晰):

    var range = [{ min: 100, max: 999 }];
    
    var data = [
     {Id:'1' , Title: 'Group A' , Start: 100 , End:200 }, 
     {Id:'2' , Title: 'Group B' , Start: 350 , End:500 },
     {Id:'3' , Title: 'Group C' , Start: 600 , End:800 }
    ];
    
    
    for (let i=0; i<data.length; ++i) {
    
        for (let r=0;r<range.length; ++r) {
    
            // check if this data matches the existing data
            // update existing data rather than create a new entry
            if (range[r].min == data[i].Start) {
                range[r].min = data[i].End+1;
                break;
            }
            
            // check if this data sits inside the range
            if (range[r].max > data[i].Start) {
                // split the range, end one where data starts and add another where data ends
                // (add the end part first before changing existing range[r].max)
                range.push({ min: data[i].End+1, max: range[r].max})
                range[r].max = data[i].Start-1;
                break;
            }
        }
    }
    
    console.log(range);

    如果您的数据从超出范围开始,那么您需要删除 max&lt;min 的位置 对此条件进行显式检查。

    这使用了输出数据没有任何重叠数据的先决条件(排序顺序无关紧要,但输出顺序也不会被排序)。

    您可以在输出中将 min/max 更改为 Start/End,为清楚起见,为它们保留不同的名称。

    我也将 data.Start/data.End 转换为数字,但如果您愿意,您可以在脚本中添加它(.Start*1 无处不在或其他首选的字符串到整数的转换)。

    【讨论】:

      【解决方案3】:

      这里有一个示例,说明如何在 javascript 中执行此操作。您可以使用 for 循环遍历对象,并可以通过从当前行选择 End+1 和从下一行选择 Start-1 为输入对象中的每一行创建一行。最后一行 End 将是 999。

      output 是您想要的结果。

      var p = [
               {Id:'1' , Title: 'Group A' , Start: '100' , End:'200'} , 
               {Id:'2' , Title: 'Group B' , Start: '350' , End:'500'} ,
               {Id:'3' , Title: 'Group C' , Start: '600' , End:'800'} 
              ];
      
      var i;
      var output = [];
      
      for (i = 0; i < p.length; i++) {
        if (i + 1 < p.length)
          output.push({ Start: Number(p[i].End) + 1, End: Number(p[i + 1].Start) - 1 });
        else
          output.push({ Start: Number(p[i].End) + 1, End: 999 });
      }
      
      console.log(output);

      console.log(output); 你会得到下面的输出:

      Array [Object { Start: 201, End: 349 }, Object { Start: 501, End: 599 }, Object { Start: 801, End: 999 }]
      

      【讨论】:

      • 提示:您可以添加一个包含该输出的 sn-p,而不是“如果您输出”,然后我们可以运行它来查看它的所有荣耀。在这种情况下,我已经为您完成了。
      • @freedomn-m 非常感谢。这真是一个很棒的建议。最良好的祝愿。
      【解决方案4】:

      这是另一种稍微宽容和通用的方法,它允许任何未排序的排除数组(排除范围甚至可能重叠):

      const excl=[[400,450],[100,200],[350,500],[600,800],[150,250]],
        sortedArr = [{Id:'1' , Title: 'Group A' , Start: '100' , End:'200'} , 
             {Id:'2' , Title: 'Group B' , Start: '350' , End:'500'} ,
             {Id:'3' , Title: 'Group C' , Start: '600' , End:'800'} ];
      
      function allowedRanges(inc,excl){
      var incl=[inc];
      excl.forEach(x=>{
      incl.forEach((r,i,a)=>{
        if (x[0]<=r[1] && x[1]>=r[0])
          a.splice(i,1,[r[0],x[0]-1],[x[1]+1,r[1]])   
      });
      });
      // now, remove the nonsensical ones
      // and return the result:
      return incl.filter(r=>r[1]>r[0]);
      }
      // test with an unsorted array excl:
      console.log(allowedRanges([1,999],excl));
      // test with sortedArr:
      console.log(allowedRanges([101,999],sortedArr.map(e=>[+e.Start,+e.End])));

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-20
        • 2020-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        相关资源
        最近更新 更多