Уменьшить массив объектов без использования .push()

#javascript #arrays #functional-programming

#javascript #массивы #функциональное программирование

Вопрос:

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

 [
    {
        user: 'User_1',
        date: 1603926000000,
        count: 3,
    },
    {
        user: 'User_2',
        date: 1603926000000,
        count: 10,
    },
    {
        user: 'User_2',
        date: 1604876400000,
        count: 1,
    },
]
  

Я уменьшаю его с помощью этой функции:

 const reducedDataByDate = dataByDate.reduce((acc, d) => {
        const foundUser = acc.find((a) => a.user === d.user)
        const value = { date: formatDate(d.date), count: d.count }
        if (!foundUser) {
            acc.push({ user: d.user, data: [value] })
        } else {
            foundUser.data.push(value)
        }
        return acc
    }, [])
  

с таким результатом:

 [
    {
        user: 'User_1',
        data: [
            {
                date: '2020-10-29',
                count: 10,
            },
            {
                date: '2020-11-09',
                count: 1,
            },
        ],
    },
    {
        user: 'User_2',
        data: [
            {
                date: '2020-10-29',
                count: 3,
            },
        ],
    },
]
  

В идеале я хотел бы избавиться от переноса значений в original acc и foundUser array, но мало представляю, как это сделать. Любой ввод приветствуется!

Комментарии:

1. что вы хотите вместо этого?

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

3. foundUser.data[foundUser.data.length] = value

Ответ №1:

Вы можете собрать данные с помощью a Map и получить из них нужный формат.

 const 
    data = [{ user: 'User_1', date: 1603926000000, count: 3 }, { user: 'User_2', date: 1603926000000, count: 10 }, { user: 'User_2', date: 1604876400000, count: 1 }],
    result = Array.from(
        data.reduce(
            (m, { user, ...o }) => m.set(user, [...(m.get(user) || []), o]),
            new Map
        ),
        ([user, data]) => ({ user, data })
    );

console.log(result);  
 .as-console-wrapper { max-height: 100% !important; top: 0; }  

Комментарии:

1. Спасибо, это действительно работает! Однако я не совсем понимаю, что здесь происходит ([user, data]) => ({ user, data }) . Не могли бы вы это прояснить?

2. Array.from принимает итерацию, сопоставление, которое совпадает с тем, Map#entries которое возвращает массив массивов с парами ключ / значение, и этот массив сопоставляется с использованием ключа / user и значения / data в качестве коротких свойств для нового объекта.