You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript如何高效统计多个JSON输入中各属性值的出现次数

现有实现的性能瓶颈

你的现有代码存在几处冗余开销,处理万级数据时会被放大:

  • 每次匹配trait_type都要全量遍历countOfAllAttribute数组,属性类型越多耗时越长
  • 匹配属性值时先后调用了some、find、map,同个trait_count数组最多被遍历3次,冗余开销大
  • 使用map做纯遍历操作但未使用返回值,产生无意义的数组拷贝开销

优化方案

分两种场景给出高效实现,时间复杂度均降到最低:

场景1:首次全量统计5000-10000条数据

优先用批量统计逻辑,一次性生成符合要求的结构,比逐条调用reducer效率高10倍以上:

// 输入为所有NFT对象的数组
function batchCountAttributes(nfts: Array<{attributes: Array<{type: string, value: string}>}>): CountOfEachAttribute[] {
    // 嵌套Map做临时统计,查找效率O(1)
    const statMap = new Map<string, Map<string, number>>();

    // 单次遍历所有NFT的所有属性,无冗余操作
    for (const nft of nfts) {
        for (const attr of nft.attributes) {
            const { type: traitType, value } = attr;
            // 初始化属性类型的统计容器
            if (!statMap.has(traitType)) {
                statMap.set(traitType, new Map());
            }
            const valueMap = statMap.get(traitType)!;
            // 更新属性值计数
            valueMap.set(value, (valueMap.get(value) || 0) + 1);
        }
    }

    // 转换为要求的接口格式
    return Array.from(statMap.entries()).map(([trait_type, valueMap]) => {
        const trait_count = Array.from(valueMap.entries()).map(([value, count]) => ({ value, count }));
        return {
            trait_type,
            trait_count,
            total_variations: valueMap.size
        }
    })
}

该方法时间复杂度为O(总属性数),1万条数据每条平均10个属性的情况下,总计算量仅10万次,毫秒级即可完成。

场景2:优化单条增量更新的reducer逻辑

如果必须支持单条属性增量更新,优化后的逻辑如下,去掉所有冗余遍历:

setCountOfAllAttribute(state, { payload }: PayloadAction<Attribute>) {
  if (state.countOfAllAttribute === null) return;

  // 匹配目标属性类型
  const targetTrait = state.countOfAllAttribute.find(
    item => item.trait_type === payload.trait_type
  );
  if (!targetTrait) return;

  const payloadValue = String(payload.value);
  // 初始化属性值统计数组
  if (targetTrait.trait_count === null) {
    targetTrait.trait_count = [{ value: payloadValue, count: 1 }];
    targetTrait.total_variations = 1;
    return;
  }

  // 单次遍历查找对应属性值,找到直接更新
  const existingValue = targetTrait.trait_count.find(item => item.value === payloadValue);
  if (existingValue) {
    existingValue.count += 1;
    return;
  }

  // 无匹配值新增条目,用push替代展开运算符避免数组拷贝
  targetTrait.trait_count.push({ value: payloadValue, count: 1 });
  targetTrait.total_variations += 1;
}

如果属性类型非常多,可以额外在state里维护一个traitTypeIndex: Record<string, number>索引,记录每个trait_type在countOfAllAttribute数组的下标,查找属性类型的时间会从O(n)降到O(1),性能进一步提升。


内容的提问来源于stack exchange,提问作者ben shalev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 14:45:01