首页 > 解决方案 > 如何从系列中提取连续天数?

问题描述

我正在尝试编写一个递归函数来查找数组中连续天的开始和结束索引。

这是我的示例输入:

var input =  [
    '2018-06-11',
    '2018-06-12',
    '2018-06-15',
    '2018-06-16',
    '2018-06-17',
    '2018-06-19'
];

我希望我的输出是:

var expectedOutput = [{
        start: '2018-06-11',
        end: '2018-06-12'
    },
    {
        start: '2018-06-15',
        end: '2018-06-17'
    },
    {
        start: '2018-06-19',
        end: '2018-06-19'
    }
];

所以我想找到连续几天的开始/结束日期。

个人的日子应该是自己的。

我写了一个算法,但它在第一天就停止了。

function extractConsecutiveDays(input, index) {

    if (input == null || input.length === 0) {
        return;
    }

    if(isConsecutiveDay(input[index], input[index + 1])) {
        return extractConsecutiveDays(input, index + 1);
    }

    var obj = {
        start: input[0],
        end: input[index]
    };

    input.splice(0, index);
    return obj;
}

这是我的小提琴: https ://jsfiddle.net/aubz88/tz24o0fk/

标签: javascriptrecursion

解决方案


我在上面问过你为什么想要一个递归解决方案(这个问题并不适合它),听起来你对非递归解决方案持开放态度。如果是这样,请参阅评论:

function findConsecutive(array) {
    var result = [];
    var current = null;
    // Loop through building up each result, starting a new entry each
    // time we find a non-consecutive day
    array.forEach(function(entry) {
        // If this is the first pass or this entry isn't consecutive with
        // the last, start a new entry
        if (!current || !areConsecutive(current.end, entry)) {
            result.push(current = {
              start: entry,
              end: entry
            });
        } else {
            // It's consecutive, just extend the last one
            current.end = entry;
        }
    });
    return result;
}

现场示例:

var input =  [
    '2018-06-11',
    '2018-06-12',
    '2018-06-15',
    '2018-06-16',
    '2018-06-17',
    '2018-06-19'
];

// I *THINK* this `areConsecutive` implementation is reliable across DST
// boundaries (http://jsfiddle.net/em8xqtc2/3/), but be sure to test...
var ONE_DAY_IN_MILLIS = 86400000;
function toDateUTC(str) {
  var parts = str.split("-");
  return Date.UTC(+parts[0], +parts[1] - 1, +parts[2]);
}
function areConsecutive(a, b) {
  return toDateUTC(b) - toDateUTC(a) == ONE_DAY_IN_MILLIS;
}

function findConsecutive(array) {
    var result = [];
    var current = null;
    // Loop through building up each result, starting a new entry each
    // time we find a non-consecutive day
    array.forEach(function(entry) {
        // If this is the first pass or this entry isn't consecutive with
        // the last, start a new entry
        if (!current || !areConsecutive(current.end, entry)) {
            result.push(current = {
              start: entry,
              end: entry
            });
        } else {
            // It's consecutive, just extend the last one
            current.end = entry;
        }
    });
    return result;
}

var expectedOutput = findConsecutive(input);
console.log(expectedOutput);
.as-console-wrapper {
  max-height: 100% !important;
}

我在那里只使用了 ES5 级别的功能,因为您出现在您的解决方案中。但是,如果您使用 ES2015+,则不会有太大变化:

const input =  [
    '2018-06-11',
    '2018-06-12',
    '2018-06-15',
    '2018-06-16',
    '2018-06-17',
    '2018-06-19'
];

// I *THINK* this `areConsecutive` implementation is reliable across DST
// boundaries (http://jsfiddle.net/em8xqtc2/3/), but be sure to test...
const ONE_DAY_IN_MILLIS = 86400000;
function toDateUTC(str) {
  const [year, month, day] = str.split("-");
  return Date.UTC(+year, +month - 1, +day);
}
function areConsecutive(a, b) {
  return toDateUTC(b) - toDateUTC(a) == ONE_DAY_IN_MILLIS;
}

function findConsecutive(array) {
    const result = [];
    let current = null;
    // Loop through building up each result, starting a new entry each
    // time we find a non-consecutive day
    for (const entry of array) {
        // If this is the first pass or this entry isn't consecutive with
        // the last, start a new entry
        if (!current || !areConsecutive(current.end, entry)) {
            result.push(current = {
              start: entry,
              end: entry
            });
        } else {
            // It's consecutive, just extend the last one
            current.end = entry;
        }
    }
    return result;
}

const expectedOutput = findConsecutive(input);
console.log(expectedOutput);
.as-console-wrapper {
  max-height: 100% !important;
}


推荐阅读