Как отфильтровать последний день в массиве? - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть массив таких объектов:

[
    {
        created: "2019-08-14T13:24:36Z",
        email: "test1@gmail.com"
    },
    {
        created: "2019-08-15T13:24:36Z",
        email: "test2@gmail.com"
    },
    {
        created: "2019-08-16T13:24:36Z",
        email: "test1@gmail.com"
    },
    {
        created: "2019-08-22T13:24:36Z",
        email: "test4@gmail.com"
    },
    {
        created: "2019-08-22T15:29:66Z",
        email: "test1@gmail.com"
    }
]

Массив отсортирован по created. Я хочу filter те записи, которые находятся в последний день, независимо от времени в этот день. Я добавил метку времени, используя moment.js. Что-то на этих строках:

router.get('/GetLastDayRecords', (req, res) => {
    res.json(allRecords.filter(record => record.created.max()));
});

Ответы [ 6 ]

2 голосов
/ 07 ноября 2019

Разделите задачу: сначала получите максимальную дату, которую вы найдете в конце отсортированного массива (достаточно получить только часть "YYYY-MM-DD"), а затем запустите фильтр:

let max = allRecords.length ? allRecords[allRecords.length-1].created.slice(0,10) : "";
res.json(allRecords.filter(({created}) => created >= max));
0 голосов
/ 07 ноября 2019

Предполагая, что массив уже ASC упорядочен:

const onLastDay = values.filter( v => {
  const last = moment(values[ values.length - 1 ].created)
  const differenceInDays = last.diff(moment(v.created), 'days')
  return differenceInDays < 1
})

console.log(onLastDay)

ПРИМЕЧАНИЕ: Если вы попытаетесь использовать указанный массив, вы получите ошибку из-за того, что последняя датанедействительный! 66 секунд!

0 голосов
/ 07 ноября 2019

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

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

const dateToInt = date => parseInt( date.split('T').shift().replace(/-/g, '') );

Выше будет:

  • Разделите созданное свойство на массив даты и времени.
  • Выберите первый элемент, который является датой.
  • Удалите тире в дате.
  • Приведите значение в число.

С его помощью вы можете найти максимальное значение и фильтр на основе этого значения.


const nums = foo.map( ({ created }) => dateToInt(created) )

Сначала получите списокчисел из набора данных.

const max = Math.max( ...nums )

Получить наибольшее число в списке.

const lastDays = foo.filter( ({ created }) => dateToInt(created) === max )

При всех этих настройках получение максимальной даты очень просто и читабельно.


Конечно, поскольку список уже отсортирован. Вы могли бы также сделать это.

const last = foo[foo.length -1].created;

const lastDays = foo.filter( ({ created }) => created === last )
0 голосов
/ 07 ноября 2019

Я написал решение, используя Reduce и Filter:

const lastDay = arr.reduce((acc, el) => {
    const date = el.created.substr(0,10);
    const oldDate = new Date(acc);
    const nextDate = new Date(date);
    if(oldDate.getTime() > nextDate.getTime()) {
        return oldDate;
    } else {
        return nextDate;
    }
}, '1900-01-01');

const lastDayArr = arr.filter(el => {
    const date = el.created.substr(0,10);
    const oldDate = new Date(lastDay);
    const nextDate = new Date(date);
    return (oldDate.getTime() === nextDate.getTime());
});

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

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

Конечным результатом является массив элементов с самой последней датой в исходном массиве.

Если выМожно предположить, что массив отсортирован, вы можете пропустить метод Reduce и просто выполните:

const lastDay = arr[arr.length - 1].created.substr(0,10);
0 голосов
/ 07 ноября 2019

Это должно работать:

allRecords.filter( record => {
    let last_date = allRecords[ allRecords.length - 1].created
    return last_date.slice(0, 10) === record.created.slice(0, 10)
})

По сути, вы получаете последний элемент из вашего массива и разрезаете его значение created до даты. Затем вы нарезаете значение created текущей записи до даты и сравниваете, совпадают ли они.

0 голосов
/ 07 ноября 2019

Сначала вам нужно выяснить, какой день является последним днем. Если вы можете предположить, что записи уже отсортированы, то это довольно просто:

// Assuming your records are stored in the variable "records"

var lastDay = records[records.length - 1].created;

Теперь вот где ваш конкретный ответ может отличаться в зависимости от того, как вы хотитеобрабатывать часовые пояса. Предположим, что одно событие произошло в 23:00 по восточному поясному времени (3 часа по Гринвичу), а другое - в 1 час по восточному времени (5 часов утра по Гринвичу)Это один и тот же день? В Европе они есть, а в Америке - нет!

Что вам нужно сделать, так это создать какой-нибудь шифр из даты и времени, указанных в «дне». Таким образом, вы можете сравнить два «дня», чтобы увидеть, совпадают ли они:

lastDay = new Date(lastDay);
// Setting hours, minutes, and seconds to 0 will give you just the "day" without the time, but by default will use the system timezone
lastDay.setHours(0);
lastDay.setMinutes(0);
lastDay.setSeconds(0);

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

// Using a for loop
var results = []
for (var i = 0; i < records.length; i++)
{
    if (records[i].created > lastDay) {
        results.push(records[i]);
    }
}

// Using .filter
var results = records.filter(x => x.created > lastDay);

В качестве альтернативы, поскольку мы знаем, что она уже отсортирована, мы можем сделать это немного более эффективно, выполнив двоичный поиск первой записи в последний день, а затем собрав все записи после этого:

var test = records.length / 2;
var step = records.length / 4;
var found = false;
while (!found) {
    if (records[test].created < lastDay) {
        test += step;
        step /= 2;
    }
    else if (records[test].created > lastDay) {
        if (step == 1) {
            // We found the exact cut-off
            found = true;
        }
        else {
            test -= step;
            step /= 2;
        }
    }
}

var results = records.slice(test);

Поскольку вы толькоинтересует «последний» день, логика немного проще. Если вы хотите «третий» день, вам нужно проверить, было ли created после начала третьего дня и до конца третьего дня. Мы можем просто проверить, наступило ли это после начала последнего дня.

...