将数组中的每个元素与其他每个元素进行比较

Tet*_*Dev 3 javascript arrays reduce compare overlap

我需要比较时间表的重叠情况,从 2 个到无限多个时间表。

例如,具有 3 个计划的数组将如下所示:

var dateRanges =  [
    {
      DaysOfWeek: ['Sun', 'Mon'],
      StartTime: "01:00",
      StopTime: "17:00",
      AllDay: false
    },
    {
      DaysOfWeek: ['Tues', 'Wed'],
      StartTime: "12:00",
      StopTime: "21:59",
      AllDay: true
    },
            {
      DaysOfWeek: ['Thur', 'Sun'],
      StartTime: "12:00",
      StopTime: "21:59",
      AllDay: true
    }
  ]
Run Code Online (Sandbox Code Playgroud)

我正在努力弄清楚如何将所有数组相互比较。到目前为止我有这个

checkScheduleForOverlap: function (dateRanges) {

  var result = dateRanges.reduce((result, current, i, arr) => {
    // console.log(previous, current);

    // get the previous range
    if (i === 0) { return result; }
    var previous = arr[i - 1];

    // Schedule1
    var startTime1 = new Date('1970-01-01T' + previous.StartTime + 'Z');
    var stopTime1 = new Date('1970-01-01T' + previous.StopTime + 'Z');

    // Schedule2
    var startTime2 = new Date('1970-01-01T' + current.StartTime + 'Z');
    var stopTime2 = new Date('1970-01-01T' + current.StopTime + 'Z');

    previous.DaysOfWeek.forEach(function (prevDay) {

      console.log(prevDay);
      current.DaysOfWeek.forEach(function (currDay) {
        console.log(currDay);

        if (prevDay === currDay) {
          var overlap = (startTime1 <= stopTime2) && (stopTime1 >= startTime2);

          // store the result
          if (overlap) {
            // yes, there is overlap
            result.overlap = true;
            // store the specific ranges that overlap
            result.days.push(currDay);
          }
        }
      });
    });

    return result;

    // seed the reduce
  }, { overlap: false, days: [] });

  // return the final results
  console.log(result);
  return result;

}
Run Code Online (Sandbox Code Playgroud)

但它只将第二个数组与第一个数组进行比较,将第三个数组与第二个数组进行比较。它还需要将第三个与第一个进行比较。(如果有 4 个时间表,则每个时间表都需要与另一个进行比较。)

我是否走在正确的轨道上,可以采取什么措施让每个 DaysOfWeek 计划将 StartTime 和 StopTime 与其他计划中的值进行比较?

我使用静态日期创建了一个假日期对象,并且仅比较时间值。

如果这不是一种有效的方法,我愿意以完全不同的方式来做这件事。

use*_*291 5

让我们重点关注问题中有关比较多个数组之间的项目的部分。目前比较的实际逻辑并不重要。

这一切都从嵌套的 for 循环开始:

var arr1 = [ "A", "B", "C" ];
var arr2 = [ "1", "2", "3" ];

// Runs arr1.length * arr2.length = 9 times
for (let i = 0; i < arr1.length; i += 1) {
  for (let j = 0; j < arr2.length; j += 1) {
    console.log(
      "run", i * arr2.length + j, 
      "result", arr1[i], arr2[j]
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

一旦你有了一个循环遍历两个数组的所有对的函数,剩下要做的就是从单个数组列表中找到所有可能的对:

const arrays = [ [ "A" ], [ "B" ], [ "C" ] ];

for (let i = 0; i < arrays.length - 1; i += 1) {
//                                ^^^
  for (let j = i + 1; j < arrays.length; j += 1) {
//             ^^^^^
    console.log(
      JSON.stringify(arrays[i]), 
      JSON.stringify(arrays[j])
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们已经掌握了基础知识,我们可以将它们链接在一起并进行重构。我不得不承认,重构有点个人品味,将循环包装for在函数中而不需要其他更改是完全可以的。

我将第一个原则命名为combinations,并使用reducemap代替for循环。第二个for循环现在包含在allPairs.

// Utilities:
const combinations = ([xs, ys]) => 
  xs.reduce(
    (cs, x) => cs.concat(ys.map(y => [x, y])),
    []
  );
  
const allPairs = (xs) => 
  xs.reduce(
    (ps, x, i) => ps.concat(xs.slice(i + 1).map(y => [x, y])),
    []
  );

const flatten = xxs => xxs.reduce((xs, ys) => xs.concat(ys))

const findMatches = (matchFn, arrays) => flatten(
    allPairs(arrays).map(combinations)).filter(matchFn);

// App:
// Let's just stick to an easy example
const overlap = ([x, y]) => x === y;

console.log(
  findMatches(
    overlap, 
    [ [ 1, 2 ], [ 1, 3 ], [ 1, 2, 3], [ 4, 5 ], [ 1 ] ]
  )
);
  
Run Code Online (Sandbox Code Playgroud)

这种方法会返回成对的重叠元素。您必须包含您自己的overlaps功能。find您可以通过使用代替来提高效率filter,它返回第一个重叠对。如果你真的想尽早返回,甚至在构建所有对组合之前,你就必须移动更多的东西(但我无法想象性能会成为问题)。