массив нескольких фильтров и назначение переменных одновременно - PullRequest
0 голосов
/ 03 октября 2019

У меня есть следующий оператор forEach:

reviews.forEach(review => {
    if (review.timestamp >= beforeThreeMonthsDate) {
        lastThreeMonths.push(review);
    }
    if (review.timestamp >= beforeSixMonthsDate) {
        lastSixMonths.push(review);
    }
    if (review.timestamp >= beforeOneYearDate) {
        lastYear.push(review);
    }
    if (review.timestamp >= beforeTwoYearsDate) {
        lastTwoYear.push(review);
    }
});

Есть ли способ получить тот же результат с повторением всего один раз по списку reviews с использованием filter или любая новая ES6 функциональность

Ответы [ 5 ]

3 голосов
/ 03 октября 2019

Это немного меняет вывод, но вы можете reduce для объекта. вместо 4 отдельных переменных.

const {
  lastThreeMonths,
  lastSixMonths,
  lastYear,
  lastTwoYear
} = reviews.reduce(
  (groups, review) => {
    if (review.timestamp >= beforeThreeMonthsDate) {
      groups.lastThreeMonths.push(review);
    }
    if (review.timestamp >= beforeSixMonthsDate) {
      groups.lastSixMonths.push(review);
    }
    if (review.timestamp >= beforeOneYearDate) {
      groups.lastYear.push(review);
    }
    if (review.timestamp >= beforeTwoYearsDate) {
      groups.lastTwoYear.push(review);
    }
  },
  { lastThreeMonths: [], lastSixMonths: [], lastYear: [], lastTwoYear: [] }
);

Это действительно похоже на функцию groupBy.

Но я бы подумал о том, как эта информация используется. Если бы это было для слоя представления, я бы подумал о сортировке, а затем об использовании функции типа takeUntil для гибкости. Если вам нужно lastWeek, lastDay и более, то предыдущее и оригинальное решения могут оказаться громоздкими.

const takeUntil = (pred, list) =>
  list.reduce((taken, next) => (pred(next) ? taken.concat(next) : taken), []);
const sinceTwoDays = takeUntil(review => review.timestamp >= twoDaysAgo, reviews);

Этот способ повторяется как минимум в 2 раза, но дает большую гибкость в будущем. Вы можете передать любую дату и вернуть ее.

2 голосов
/ 03 октября 2019

Вы можете использовать Array.reduce. Вы также можете сделать эту функцию довольно универсальной, сократив ее до массива и (необязательно) деструктурируя , чтобы извлечь каждый вложенный массив в виде отдельной переменной. Таким образом, вам не нужно определять каждое имя ключа внутри функции. Однако результат может или не может считаться «чище», в зависимости от ваших целей. Например, см. Функцию getReviewsSince() во фрагменте ниже:

// Don't mind these functions, they're just for the sake of a working example snippet
const writeLine = (() => {
  const preEl = document.querySelector('.js-pre')
  return (s = '') => preEl.textContent += `${s}\n`
})()

const writeArr = (name, arr) => {
  writeLine(name)
  arr.forEach(r => writeLine(JSON.stringify(r)))
  writeLine()
}

const getExampleReviews = () => {
  let i = 0
  return [
    { id: i++, timestamp: 1562166556565 },
    { id: i++, timestamp: 1514985756565 },
    { id: i++, timestamp: 1514995756565 },
    { id: i++, timestamp: 1562165556565 },
    { id: i++, timestamp: 1451837356565 },
    { id: i++, timestamp: 1451837356565 },
  ]
}

// ---

// Get an array - each element is a nested array for the matching timestamp
const getReviewsSince = (reviews, timestamps) =>
  reviews.reduce((arr, review) => {
    timestamps.forEach((ts, idx) => {
      if (review.timestamp >= ts) {
        arr[idx].push(review)
      }
    })
    return arr
  }, timestamps.map(() => []))

// Example usage of getReviewsSince() w/ destructuring
const reviews = getExampleReviews()
const [
  lastThreeMonths,
  lastSixMonths,
  lastYear,
  lastTwoYears,
] = getReviewsSince(reviews, [
  1562166556565,
  1546531756565,
  1514995756565,
  1451837356565,
])

// Output the results for us to see
writeArr('lastThreeMonths', lastThreeMonths)
writeArr('lastSixMonths', lastSixMonths)
writeArr('lastYear', lastYear)
writeArr('lastTwoYears', lastTwoYears)
0 голосов
/ 03 октября 2019

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

reviews.forEach(review => {
    review.timestamp >= beforeThreeMonthsDate && lastThreeMonths.push(review);
    review.timestamp >= beforeSixMonthsDate && lastSixMonths.push(review);
    review.timestamp >= beforeOneYearDate && lastYear.push(review);
    review.timestamp >= beforeTwoYearsDate && lastTwoYear.push(review);
});
0 голосов
/ 03 октября 2019

Ваш подход великолепен, но если вы хотите чище, я произвел что-то вроде этого:

let lastThreeMonths  = [];
let lastSixMonths    = [];
let lastYearMonths   = [];
let lastTwoYears     = [];

reviews.forEach(review => {
    if (review.timestamp >= beforeThreeMonthsDate) {
        lastThreeMonths = [...lastThreeMonths, review];
    }
    else if (review.timestamp >= beforeSixMonthsDate) {
        lastSixMonths = [...lastSixMonths, review];
    }
    else if (review.timestamp >= beforeOneYearDate) {
        lastYear = [...lastYear, review ];
    }
    else if (review.timestamp >= beforeTwoYearsDate) {
        lastTwoYear = [...lastTwoYear, review];
    }
});

Вы можете проверить документы разрушающего назначения Здесь :

0 голосов
/ 03 октября 2019

Поскольку в вашем коде уже есть только один цикл, я не уверен, что вам нужно для "с циклом всего один раз".

С помощью фильтра вы можете сделать это.

lastThreeMonths = reviews.filter(review => review.timestamp >= beforeThreeMonthsDate);
lastSixMonths = reviews.filter(review => review.timestamp >= beforeSixMonthsDate);
lastYear = reviews.filter(review => review.timestamp >= beforeOneYearDate);
lastTwoYear = reviews.filter(review => review.timestamp >= beforeTwoYearsDate);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...