【问题标题】:Counting multiple json inputs js计算多个json输入js
【发布时间】:2021-11-28 05:02:40
【问题描述】:

我收到这样的输入:

input 1:

{

"name": "Ben",
"description": "Ben",
"attributes": [
    {
    "type": "Background",
    "value": "Default"
    },
    {
    "type": "Hair-color",
    "value": "Brown"
    }
]
}

input 2

{

"name": "Ice",
"description": "Ice",
"attributes": [
    {
    "type": "Background",
    "value": "Green"
    },
    {
    "type": "Hair-color",
    "value": "White"
    }
]
}

input 3

{

"name": "Itay",
"description": "Itay",
"attributes": [
    {
    "type": "Background",
    "value": "Default"
    },
    {
    "type": "Hair-color",
    "value": "Brown"
    }
]
}

我要做的是计算每种背景和每种头发颜色出现的数量。 (这些是示例示例,实际上有更多类型和不同的值)

假设在这些示例中,我们有 2 个默认背景为背景的对象,那么我想要这样计数:

export interface TraitCount {
    value: string,
    count: number
}

export interface CountOfEachAttribute {
    trait_type: string,
    trait_count: traitCount[] | null,
    total_variations: number
}

我想要最有效的代码,因为代码还有其他方面,此外它将在 5-10k 查询上运行,而不仅仅是三个,所以需要 也可以在美好的时光中奔跑:D (这类似于我用 python 完成的另一个问题,但现在我也需要它在 js 中)

ATM 是这样的:

(除了更大的代码,请记住这一点)

    setInitalCountOfAllAttribute( state, { payload }: PayloadAction<CountOfEachAttribute[] | null> ) {
      if (payload === null) {
        state.countOfAllAttribute = null;
      } else {
        state.countOfAllAttribute = payload;
      }
    },

    setCountOfAllAttribute(state, { payload }: PayloadAction<Attribute>) {

      if (state.countOfAllAttribute !== null) {
        state.countOfAllAttribute.map(
          (countOfEachAttribute: CountOfEachAttribute) => {

            // Find the trait type
            if (countOfEachAttribute.trait_type === payload.trait_type) {

              // initiate the trait count array to store all the trait values and add first trait value
              if (countOfEachAttribute.trait_count === null) {
                const new_trait_count = { value: payload.value, count: 1 };
                countOfEachAttribute.trait_count = [new_trait_count];
                countOfEachAttribute.total_variations++;
              } 

              // Trait array already existed. 
              else {

                // Check if value already present or not
                const checkValue = (obj: any) => obj.value === String(payload.value);
                const isPresent = countOfEachAttribute.trait_count.some(checkValue)
                const isPresent2 = countOfEachAttribute.trait_count.find((elem: any) => elem.value === String(payload.value))

                // Value matched, increase its count by one
                  if (isPresent2) {
                  countOfEachAttribute.trait_count &&
                    countOfEachAttribute.trait_count.map((trait) => {
                      if (trait.value === payload.value) {
                        trait.count++;
                      }
                    });
                } 

                // Value doesn't match, add a new entry and increase the count of variations by one
                else {
                  const new_trait_count = { value: payload.value, count: 1 };
                  countOfEachAttribute.trait_count = [
                    ...countOfEachAttribute.trait_count,
                    new_trait_count,
                  ];
                  countOfEachAttribute.total_variations++;
                }
              }
            }
          }
        );
      }
    },

【问题讨论】:

  • 到目前为止你尝试了什么?
  • @KrzysztofKrzeszewski 更新了已经尝试过的问题,太慢了

标签: javascript json typescript formatting counting


【解决方案1】:

您可以合并所有数组并使用Array.reduce

const input1 = {
  "name": "Ben",
  "description": "Ben",
  "attributes": [{
      "type": "Background",
      "value": "Default"
    },
    {
      "type": "Hair-color",
      "value": "Brown"
    }
  ]
}
const input2 = {
  "name": "Ice",
  "description": "Ice",
  "attributes": [{
      "type": "Background",
      "value": "Green"
    },
    {
      "type": "Hair-color",
      "value": "White"
    }
  ]
}
const input3 = {
  "name": "Itay",
  "description": "Itay",
  "attributes": [{
      "type": "Background",
      "value": "Default"
    },
    {
      "type": "Hair-color",
      "value": "Brown"
    }
  ]
}

const mergedInput = [input1, input2, input3];

const result = mergedInput.reduce((acc, item) => {
  
  item.attributes.forEach(attrItem => {
    const existType = acc.find(e => e.trait_type == attrItem.type);
    if (existType) {
        var existAttr = existType.trait_count.find(e => e.value == attrItem.value);
      if (existAttr) {
        existAttr.count++;
      } else {
        existType.trait_count.push({
            value: attrItem.value,
          count: 1
        });
        existType.total_variations++;
      }
    } else {
        acc.push({
        trait_type: attrItem.type,
        trait_count: [{
            value: attrItem.value,
          count: 1
        }],
        total_variations: 1
      })
    }
  });
  return acc;
}, []);

console.log(result);

【讨论】:

  • 合并它是否适用于 5-10k 输入?
  • @benshalev 你有收到一一输入吗?
  • 是的,我们查询一个API,我们会一一获取这些属性。
  • @benshalev 我认为您不应该一一处理并将其设置为状态。它也使您的应用程序重新加载。你能把所有对 API 的查询移到一个函数中,然后将它们全部合并到一个数组中吗?
  • 我们会尝试合并,我今天测试一下看看。合并不会导致延迟(因为它是 10k api,数据比这多一点)?
【解决方案2】:

我建议不要为 trait_count 创建一个数组以使其成为一个对象,这样您就不必在添加新属性时对其进行迭代。在下面的 sn-p 中,我使用属性的值作为一种哈希,允许访问给定的属性而无需调用 Array.prototype.find 函数

const input1 = {"name":"Ben","description":"Ben","attributes":[{"type":"Background","value":"Default"},{"type":"Hair-color","value":"Brown"}]};
const input2 = {"name":"Ice","description":"Ice","attributes":[{"type":"Background","value":"Green"},{"type":"Hair-color","value":"White"}]};
const input3 = {"name":"Itay","description":"Itay","attributes":[{"type":"Background","value":"Default"},{"type":"Hair-color","value":"Brown"}]};

function countAtributes(input, totalCounts={}) {
  input.attributes.forEach((attribute) => {
    if (!totalCounts[attribute.type])
      totalCounts[attribute.type] = {trait_type: attribute.type, trait_count: {}, total_variations: 0};

    if (!totalCounts[attribute.type].trait_count[attribute.value]) {
      totalCounts[attribute.type].trait_count[attribute.value] = {value: attribute.value, count: 1};
      totalCounts[attribute.type].total_variations+=1;
    }
    else totalCounts[attribute.type].trait_count[attribute.value].count +=1;
  })
}

const totalCounts = {};
countAtributes(input1, totalCounts);
countAtributes(input2, totalCounts);
countAtributes(input3, totalCounts);

console.log(totalCounts);

如果需要,可以在之后使用Object.values 将其转换为数组

我相信这是一种比以前更好的方法,因为您不必遍历 trait_counts 表。从理论上讲,它应该显着减少所花费的时间。每次遍历数组并检查一个条件比key lookup in Javascript object慢得多

【讨论】:

  • 如果我们一个一个地查询一个API来获取数据(5-10k个查询),它是如何工作的
  • 请阅读我答案底部的注释
  • 好的,我会测试这些答案并在今晚晚些时候更新你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多