如何生成特定的字符串数组?

时间:2019-06-19 19:23:56

标签: javascript arrays date

我有以下问题。我有一个数组:

const dates = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019", "14-June-2019"]

我需要生成一个日期数组,该数组在我表示行中的日期之后。 所以:

const datesInRow = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019"]

这是我的初始函数:(isAfter函数= date-fns)

 function numberOfDaysInRow(arr) {
  if (arr.length === 1) return arr;
  let numberOfDaysInRowArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (isAfter(new Date(arr[i]), new Date(arr[i + 1]))) {
      numberOfDaysInRowArr.push(arr[i]);
    }
  }
  return numberOfDaysInRowArr;
}

这仅返回部分答案。例如,如果我在数组中只有两个这样的字符串:

const dates = ["19-June-2019", "18-June-2019"]

它将返回

["19-June-2019"]

这不是我想要的。

6 个答案:

答案 0 :(得分:2)

您可以在循环外处理第一个元素,而仅取下一个元素。

function numberOfDaysInRow(arr) {
    if (arr.length === 1) return arr;
    let numberOfDaysInRowArr = [];

    if (isAfter(new Date(arr[0]), new Date(arr[1]))) {
        numberOfDaysInRowArr.push(arr[0]);
    }

    for (let i = 0; i < arr.length; i++) {
        if (isAfter(new Date(arr[i]), new Date(arr[i + 1]))) {
            numberOfDaysInRowArr.push(arr[i + 1]);
        }
    }
    return numberOfDaysInRowArr;
}

使用带有以下值的state变量的抽象方法:

  • 0:初始值或找不到后续日期
  • 1:发现以下日期
  • 2:序列结尾

此方法采用整数值而不是日期升序而不是降序。

仅使用找到的第一个连续数据集。

var array = [1, 3, 5, 7, 8, 9, 10, 12, 14],
    state = 0,
    result = array.filter((v, i, { [i - 1]: prev, [i + 1]: next }) => {
        switch (state) {
            case 0:
                if (v + 1 === next) {
                    state = 1;
                    return true;
                }
                break;
            case 1:
                if (prev + 1 === v) return true;
                state = 3;
                break
        }
    });

console.log(result);

答案 1 :(得分:2)

const dates = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019", "14-June-2019"]
const datesInRow = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019"]
const datesBroken = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019", "10-June-2019", "09-June-2019", "08-June-2019"]

function isAfter(date1, date2) {
  return (date1.getTime() - date2.getTime()) == 86400000;
}

function numberOfDaysInRow(arr) {
  if (arr.length === 1) return arr;
  let numberOfDaysInRowArr = [arr[0]];
  for (let i = 0; i < arr.length - 1; i++) {
    if (isAfter(new Date(arr[i]), new Date(arr[i + 1]))) {
      numberOfDaysInRowArr.push(arr[i + 1]);
    } else {
      i = arr.length - 1;
    }
  }
  return numberOfDaysInRowArr;
}

console.log(numberOfDaysInRow(dates))
console.log(numberOfDaysInRow(datesInRow))
console.log(numberOfDaysInRow(datesBroken))

您应使用numberOfDaysInRowArr初始化[arr[0]]

然后循环我直到arr.length - 1

另外,按arr[i + 1]而不是arr[i]

答案 2 :(得分:1)

可以将每个日期与上一个和下一个日期进行比较,以检查它们是否相隔一天:

const dates = ["6-June-2019", "4-June-2019", "3-June-2019", "1-June-2019"]

const filtered = dates.filter((v, i, a) => new Date(v) - new Date(a[i - 1]) > -1e8
                                        || new Date(v) - new Date(a[i + 1]) <  1e8 )

console.log( filtered )


要处理多个组并获得最大的组:

const dates = ["23-June-2019", "22-June-2019", 
               "13-June-2019", "12-June-2019", "11-June-2019", 
                                "2-June-2019",  "1-June-2019"];

let start = 0, maxCount = 0;

for (let count = 1, i = dates.length - 1; i >= 0; i--, count++) {
  if (i < 1 || new Date(dates[i - 1]) - new Date(dates[i]) > 1e8) {
    if (count > maxCount) {
      start = i; 
      maxCount = count;
    }
    count = 0; 
  }
}

console.log( dates.slice(start, start + maxCount) );


要找到第一组:

const dates = ["23-June-2019", 
               "13-June-2019", "12-June-2019", 
                "3-June-2019",  "2-June-2019",  "1-June-2019"];

const start = dates.findIndex((v, i, a) => new Date(v) - new Date(a[++i]) < 1e8);
const end = dates.findIndex((v, i, a) => i > start && new Date(v) - new Date(a[++i]) > 1e8);

console.log( dates.slice(start, end + 1) );

答案 3 :(得分:1)

您可以检查是否是您的最后一个元素...

function numberOfDaysInRow(arr) {
  if (arr.length === 1) return arr;
  let numberOfDaysInRowArr = [];
  for (let i = 0; i < arr.length; i++) {
    const isTheLastElement = i === arr.length - 1;
    const isAfterNext = () => isAfter(new Date(arr[i]), new Date(arr[i + 1])); 
    if (isTheLastElement || isAfterNext()) {
      numberOfDaysInRowArr.push(arr[i]);
    }
  }
  return numberOfDaysInRowArr;
}

现在,如果您提取条件(谓词),则可以使用filter来编写更简洁的版本...

function isLastElementOrAfterNext(string, index, stringList) {
   return index === stringList.length - 1 || isAfter(new Date(string), new Date(stringList[index + 1];
}
function numberOfDaysInRow(arr) {
   return arr.filter(isLastElementOrAfterNext);
}

您可以首先使用map改进此示例,以转换日期中的字符串...

function stringToDate(string) {
   return new Date(string);
}
function isLastElementOrAfterNext(date, index, dateList) {
   return index === dateList.length - 1 || isAfter(date, dateList[index + 1];
}
function numberOfDaysInRow(arr) {
   return arr.map(stringToDate).filter(isLastElementOrAfterNext);
}

答案 4 :(得分:1)

您不应将内置解析器用于时间戳,因为ECMA-262不支持DD-MMM-YYYY格式。另外,date-fns isAfter函数仅告诉您第一个日期是否在第二个日期之后,它不会告诉您多少。更合适的功能是differenceInDays

date-fns没有自己的解析器,它使用内置的解析器,因此我建议您使用其他库。解析器在其他问题中已经多次涉及,但是OP格式的解析器并不困难。

因此,只需从第一个日期开始,直到到达数组末尾,或者获得比上一个日期早一天以上的日期即可停止,例如

// Parser for format DD-MMM-YYYY
// Does not validate date
function parseDMY(s) {
  let months = 'jan feb mar apr may jun jul aug sep oct nov dec'.split(' ');
  let b = s.split('-');
  return new Date(b[2], months.indexOf(b[1].toLowerCase().substr(0,3)), b[0]);
}

// Return true if d1 is the day before d0
// where d0, d1 are Dates
function isPreviousDay(d0, d1) {
  // Copy dates and set to 00:00:00
  let t0 = new Date(d0);
  t0.setHours(0,0,0,0);
  let t1 = new Date(d1);
  t1.setHours(0,0,0,0);
  // Set t0 to previous day
  t0.setDate(t0.getDate() - 1);
  // See if they now have the same time value
  return t0.getTime() == t1.getTime();
}

function getContiguous(dates) {
  // Get timestamps as array of Dates
  let arr = dates.map(parseDMY);
  // Result starts with first timestamp
  let result = [dates[0]];
  // Stop comparing at second last date
  let len = dates.length - 2
  let i = 0;

  // While each date is the day before the current date,
  // add its timestamp to the result array
  while (i<len && isPreviousDay(arr[i], arr[i+1])) {
    result.push(dates[i+1]);
    i++;
  }
  return result;
}

let dates = ["19-June-2019", "18-June-2019", "17-June-2019", "16-June-2019", "14-June-2019"];

console.log(getContiguous(dates));
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>

我附加了date-fns库,但是它似乎无法正确加载,因此我编写了一个定制的 isPreviousDay 函数。

答案 5 :(得分:0)

if (isAfter(new Date(arr[i]), new Date(arr[i + 1]))) {
  numberOfDaysInRowArr.push(arr[i]);
}

如果arr [i]是数组中的最后一个元素,则arr [i + 1]将是未定义的,并且不会将任何内容推送到numberOfDaysInRowArr。