使用 vanilla JavaScript 自定义数据聚合

问题描述 投票:0回答:1

您能帮我解决以下数据聚合问题吗?

这是我的初始数组:

const data = [
    { date: '2023-11-01', type: 'A', casualties: 10, state: 'NY', country: 'USA', site: 'hash1' },
    { date: '2023-11-01', type: 'B', casualties: 5, state: 'NY', country: 'USA', site: 'hash2' },
    { date: '2023-11-02', type: 'A', casualties: 15, state: 'NY', country: 'USA', site: 'hash3' },
    { date: '2023-11-01', type: 'C', casualties: 20, state: 'NY', country: 'USA', site: 'hash4' },
    { date: '2023-11-02', type: 'B', casualties: 8, state: 'NY', country: 'USA', site: 'hash5' },
    { date: '2023-11-03', type: 'A', casualties: 25, state: 'NY', country: 'USA', site: 'hash6' },
    { date: '2023-11-01', type: 'D', casualties: 12, state: 'NY', country: 'USA', site: 'hash7' },
];

我想根据

other
值聚合
casualties
类型下的部分行。

如果给定

type
的所有日期的
casualties
等于或高于某个阈值,则它应该是
results
数组的一部分。

如果给定

type
casualties
低于所有日期的阈值,但它是唯一低于阈值的
type
,则它将成为
results
数组的一部分。

如果所有日期中有两个或多个

types
casualties
低于特定阈值, 它们不应该是
results
数组的一部分。对于这种情况,
casualties
将针对每个日期进行求和,并且
type
值应为
other

otherCasualties
数组应包含
types
低于所有日期阈值的所有
casualties

示例:

如果

casualtiesThreshold
9
,则
results
数组应该是:

results = [
    { date: '2023-11-01', type: 'A', casualties: 10, state: 'NY', country: 'USA' },
    { date: '2023-11-01', type: 'B', casualties: 5, state: 'NY', country: 'USA' },
    { date: '2023-11-02', type: 'A', casualties: 15, state: 'NY', country: 'USA' },
    { date: '2023-11-01', type: 'C', casualties: 20, state: 'NY', country: 'USA' },
    { date: '2023-11-02', type: 'B', casualties: 8, state: 'NY', country: 'USA' },
    { date: '2023-11-03', type: 'A', casualties: 25, state: 'NY', country: 'USA' },
    { date: '2023-11-01', type: 'D', casualties: 12, state: 'NY', country: 'USA' },
];

并且

otherCasualties
数组应该是
[]

如果

casualtiesThreshold
13
,则
results
数组应该是:

results = [
    { date: '2023-11-01', type: 'A', casualties: 10, state: 'NY', country: 'USA'},
    { date: '2023-11-01', type: 'other', casualties: 17, state: 'NY', country: 'USA' },
    { date: '2023-11-02', type: 'A', casualties: 15, state: 'NY', country: 'USA' },
    { date: '2023-11-01', type: 'C', casualties: 20, state: 'NY', country: 'USA' },
    { date: '2023-11-02', type: 'other', casualties: 8, state: 'NY', country: 'USA' },
    { date: '2023-11-03', type: 'A', casualties: 25, state: 'NY', country: 'USA' },
];

并且

otherCasualties
数组应该是
['B', 'D']

这是我尝试过的:

function processCasualties(data, casualtiesThreshold) {
  const results = [];
  const otherCasualties = [];

  const groupedData = data.reduce((acc, item) => {
    const key = item.type;
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(item);
    return acc;
  }, {});

  const types = Object.keys(groupedData);

  types.forEach(type => {
    const typeData = groupedData[type];
    const totalCasualties = typeData.reduce((acc, item) => acc + item.casualties, 0);
    const allDatesBelowThreshold = typeData.every(item => item.casualties < casualtiesThreshold);

    if (totalCasualties >= casualtiesThreshold || (allDatesBelowThreshold && types.length === 1)) {
      results.push(...typeData.map(item => ({
        date: item.date,
        type: item.type,
        casualties: item.casualties,
        state: item.state,
        country: item.country,
      })));
    } else if (allDatesBelowThreshold) {
      otherCasualties.push(type);
    } else {
      results.push(...typeData.map(item => ({
        date: item.date,
        type: 'other',
        casualties: totalCasualties,
        state: item.state,
        country: item.country,
      })));
    }
  });

  return { results, otherCasualties };
}

const casualtiesThreshold = 13;

const { results, otherCasualties } = processCasualties(data, casualtiesThreshold);

console.log(results);
console.log(otherCasualties);

javascript arrays aggregate
1个回答
0
投票

您可以采取两组并在第一次迭代中收集匹配的类型和其他类型。然后删除

other
集中匹配的类型,因为这些类型应该在结果集中。

最后检查

other
集中是否只有一种类型,然后将该类型也添加到结果中。

对于所有其他不匹配类型,采用

'other'
作为类型,按
date
分组。

const
    fn = (data, threshold) => {
        const
            result = [],
            other = new Set,
            match = new Set,
            others = {};
        
        for (const { type, casualties } of data) [other, match][+(casualties >= threshold)].add(type);
        
        match.forEach(Set.prototype.delete, other);
        
        if (other.size === 1) {
            match.add(...other);
            other.clear();
        }
        
        for (const { date, type, casualties, state, country, site } of data) {
            if (match.has(type)) {
                result.push({ date, type, casualties, state, country, site });
            } else {
                if (others[date]) others[date].casualties += casualties;
                else result.push(others[date] = { date, type: 'other', casualties, state, country, site });
            }
        }

        return { result, otherCasualties: [...other] };
    },
    data = [{ date: '2023-11-01', type: 'A', casualties: 10, state: 'NY', country: 'USA', site: 'hash1' }, { date: '2023-11-01', type: 'B', casualties: 5, state: 'NY', country: 'USA', site: 'hash2' }, { date: '2023-11-02', type: 'A', casualties: 15, state: 'NY', country: 'USA', site: 'hash3' }, { date: '2023-11-01', type: 'C', casualties: 20, state: 'NY', country: 'USA', site: 'hash4' }, { date: '2023-11-02', type: 'B', casualties: 8, state: 'NY', country: 'USA', site: 'hash5' }, { date: '2023-11-03', type: 'A', casualties: 25, state: 'NY', country: 'USA', site: 'hash6' }, { date: '2023-11-01', type: 'D', casualties: 12, state: 'NY', country: 'USA', site: 'hash7' }];
    
console.log(fn(data, 9));
console.log(fn(data, 13));
.as-console-wrapper { max-height: 100% !important; top: 0; }

© www.soinside.com 2019 - 2024. All rights reserved.