Сравните каждый элемент в массиве с любым другим элементом - PullRequest
0 голосов
/ 12 июня 2018

Мне нужно сравнить расписания для перекрытия, где угодно от 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
    }
  ]

I 'Я пытаюсь понять, как сравнить все массивы друг с другом.Пока у меня есть это

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;

}

Но он сравнивает только второй массив с первым, а третий со вторым.Также нужно сравнить третий с первым.(и если бы было 4 расписания, каждое из них нужно было бы сравнить с другим.)

Я на правильном пути, и что можно сделать, чтобы каждый график DaysOfWeek сравнивал StartTime и StopTime сзначения в другом расписании?

Я создал фиктивный объект даты, используя статический день, и я сравниваю только значения времени.

Я готов сделать это совершенно по-другомуесли это не эффективный способ сделать это.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Я смог заставить его работать, используя следующий код.Это может быть улучшено для эффективности, но для небольших списков, это прекрасно работает.

 /**
 * Compares to comparable objects to find out whether they overlap.
 * It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
 * A null value is interpreted as infinity
 */
checkScheduleForOverlap: function (dateRanges) {

  function dateRangeOverlaps (a_start, a_end, b_start, b_end) {
    if (a_start <= b_start && b_start <= a_end) return true; // b starts in a
    if (a_start <= b_end && b_end <= a_end) return true; // b ends in a
    if (b_start < a_start && a_end < b_end) return true; // a in b
    return false;
  }

  function multipleDateRangeOverlaps () {
    var i, j;
    if (arguments.length % 2 !== 0)
      throw new TypeError('Arguments length must be a multiple of 2');
    for (i = 0; i < arguments.length - 2; i += 2) {
      for (j = i + 2; j < arguments.length; j += 2) {
        if (
          dateRangeOverlaps(
            arguments[i], arguments[i + 1],
            arguments[j], arguments[j + 1]
          )
        ) return true;
      }
    }
    return false;
  }

  var result = {
    overlappingDays: [],
    overlap: false
  };

  // for every Schedule
  for (let i = 0; i < dateRanges.length; i++) {
    var current = dateRanges[i];

    // current Schedule
    var startTime1 = current.StartTime;
    var stopTime1 = current.StopTime;

    current.DaysOfWeek.forEach(function (currDay) {

      // console.log('currentScheduleDay', currDay);

      // for every OTHER schedule
      for (let j = 0; j < dateRanges.length; j++) {
        var nextSchedule = dateRanges[j];

        if (j === i) {
          continue;
        }

        nextSchedule.DaysOfWeek.forEach(function (nextDay) {
          // console.log('nextScheduleDay', nextDay);

          if (nextDay === currDay) {

            // next Schedule
            var startTime2 = nextSchedule.StartTime;
            var stopTime2 = nextSchedule.StopTime;

            // var overlap = (startTime1 <= stopTime2) && (stopTime1 >= startTime2);
            var overlap = multipleDateRangeOverlaps(startTime1, stopTime1, startTime2, stopTime2);

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

          }
        });
      }

    });
  }

  // remove duplicates in result

  var obj = {};

  for (var i = 0, len = result.overlappingDays.length; i < len; i++) {
    obj[result.overlappingDays[i]] = result.overlappingDays[i];
  }

  result.overlappingDays = new Array();

  for (var key in obj) {
    result.overlappingDays.push(obj[key]);
  }

  if (result.overlappingDays) {
    this.scheduleDaysOverlap = result.overlappingDays;
  }

}
0 голосов
/ 12 июня 2018

Давайте сосредоточимся на той части вашей проблемы, которая заключается в сравнении элементов между несколькими массивами.Фактическая логика сравнения пока не важна.

Все начинается с вложенного цикла 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]
    );
  }
}

Когда у вас есть функция, которая перебирает все пары двух массивов, остается только найти все возможные пары из одного списка массивов:

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])
    );
  }
}

Теперь, когда у нас есть основы, мы можем связать их вместе и выполнить рефакторинг.Я должен признать, что рефакторинг - это что-то вроде личного вкуса, совершенно нормально оборачивать циклы for в функции без других изменений.

Я назвал первый принцип combinations и использовал reduce и map вместо 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 ] ]
  )
);
  

Этот подход возвращает вам пары перекрывающихся элементов.Вы должны будете включить свою собственную функцию overlaps.Вы можете получить некоторую эффективность, используя find вместо filter, что возвращает первую перекрывающуюся пару.Если вы действительно хотите вернуться как можно раньше, прежде чем даже построить все комбинации пар, вам придется переместить еще кое-что (но я не могу представить, что производительность будет проблемой).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...