简体   繁体   中英

How to calculate sum of count of array elements of multiple arrays by order and limit?

I have 3 arrays of 3 different types. Each array contains the count of an id (which might be duplicate like arrayOfB ).

Each id has a limit value of count property is 10 (the count includes different types. Ex: if unique1 has 10 counts in type A, when process type B for unique1, it will be not processed).

const arrayOfA = [
    {
        "type": "A", "count": 10, "id": "UID1"
    },
    {
        "type": "A", "count": 20, "id": "UID2"
    },
    {
        "type": "A", "count": 1, "id": "UID4"
    },
];

const arrayOfB = [
    {
        "type": "B", "count": 5, "id": "UID1"
    },
    {
        "type": "B", "count": 5, "id": "UID3"
    },
];

const arrayOfC = [
    {
        "type": "C", "count": 6, "id": "UID1"
    },
    {
        "type": "C", "count": 6, "id": "UID4"
    },
    {
        "type": "C", "count": 3, "id": "UID2"
    },
    {
        "type": "C", "count": 3, "id": "UID3"
    },
]

The output will be like:

Map {
  'UID1|A' => 10,
  'UID2|A' => 10,
  'UID4|A' => 1,
  'UID3|B' => 5,
  'UID4|C' => 6 }

I used a set to hold id, which already has the maximum count and map to hold the output.

const maxed = new Set();
const elements = new Map();

arrayOfA.forEach(element => {
    if (element.count > 10) {
        maxed.add(`${element.id}`);
        elements.set(`${element.id}|${element.type}`, 10);
        console.log(elements)
        return;
    }

    if (elements.has(`${element.id}|${element.type}`)) {
        const newCount = elements.get(`${element.id}|${element.type}`) + element.count;
        newCount > 10 ? elements.set(`${element.id}|${element.type}`, 10) : elements.set(`${element.id}|${element.type}`, newCount);
        console.log(elements)
        return;
    }

    elements.set(`${element.id}|${element.type}`, element.count);
});

arrayOfB.forEach(element => {
    if (maxed.has(`${element.id}`)) {
        console.log(elements)
        return;
    }

    const countOfA = elements.has(`${element.id}|A`) ? elements.get(`${element.id}|A`) : 0;
    let newCount = countOfA + element.count;

    if (elements.has(`${element.id}|${element.type}`)) {
        newCount = newCount + element.get(`${element.id}|${element.type}`);
    }

    if (newCount > 10) {
        maxed.add(`${element.id}`);
        if ((10 - countOfA) > 0) elements.set(`${element.id}|${element.type}`, 10 - countOfA);
        console.log(elements)
        return;
    }

    elements.set(`${element.id}|${element.type}`, element.count);
})

arrayOfC.forEach(element => {
    if (maxed.has(`${element.id}`)) {
        console.log(elements)
        return;
    }

    const countOfA = elements.has(`${element.id}|A`) ? elements.get(`${element.id}|A`) : 0
    const countOfB = elements.has(`${element.id}|C`) ? elements.get(`${element.id}|C`) : 0

    let newCount = countOfA + countOfB + element.count;

    if (elements.has(`${element.id}|${element.type}`)) {
        newCount = newCount + element.get(`${element.id}|${element.type}`);
    }

    if (newCount > 10) {
        maxed.add(`${element.id}`);
        if ((10 - countOfA - countOfB) > 0); elements.set(`${element.id}|${element.type}`, 10 - countOfA - countOfB);
        console.log(elements)
        return;
    }

    elements.set(`${element.id}|${element.type}`, element.count);
})

I want to ask about another faster implementation if any. I estimated my big O will be O(n) (n is the total length of 3 arrays). If elements of arrays do not contain the same id.

Edit: Big thanks to you all, but seems like there's one edge case. The answers couldn't handle

var arrayOfA = [
    {
        "type": "A", "count": 10, "id": "UID1"
    },
    {
        "type": "A", "count": 20, "id": "UID2"
    },
    {
        "type": "A", "count": 1, "id": "UID4"
    },
];

const arrayOfB = [
    {
        "type": "B", "count": 5, "id": "UID1"
    },
    {
        "type": "B", "count": 5, "id": "UID3"
    },
    {
        "type": "B", "count": 1, "id": "UID3"
    },
];

var arrayOfC = [
    {
        "type": "C", "count": 6, "id": "UID1"
    },
    {
        "type": "C", "count": 6, "id": "UID4"
    },
    {
        "type": "C", "count": 3, "id": "UID2"
    },
    {
        "type": "C", "count": 3, "id": "UID3"
    },
]

In arrayOfB, I have the UID3 occurs twice, so your answers doesn't seem to work on that case.

Instead of a Set for a maxed id , you could sum the count for every id and use it for all following arrays.

 const getKey = (...a) => a.join('|'), rawData = [{ type: "A", count: 10, id: "UID1" }, { type: "A", count: 20, id: "UID2" }, { type: "A", count: 1, id: "UID4" }], rawData3 = [{ type: "B", count: 5, id: "UID1" }, { type: "B", count: 5, id: "UID3" }], rawData2 = [{ type: "C", count: 6, id: "UID1" }, { type: "C", count: 6, id: "UID4" }, { type: "C", count: 3, id: "UID2" }, { type: "C", count: 3, id: "UID3" }], elements = new Map, sums = new Map; [rawData, rawData3, rawData2].forEach(a => a.forEach(({ type, count, id }) => { var sum = sums.get(id) || 0, key = getKey(id, type); sums.set(id, sum + count); if (sum >= 10) return; if (sum + count > 10) { if (10 - sum > 0) elements.set(key, 10 - sum); return; } elements.set(key, count); })); [...elements].map(a => console.log(a.join(': '))); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Based on the assumption that you have missed to include "B" in your expected results set, two nested loops can provide the manipulation and filtering you want.

 function getIdSummary(arrays) { const maxValue = 10; //Array of objects which we later conver to a map //The aim is ease of indexing during the iterations var summary = [] //A heler to find if a maxed uid is found in the summary function isMaxed(uid) { return summary.some(item => { return item.uid === uid && item.count >= maxValue; }) } //Iterate all the arrays arrays.forEach(anInputArray => { //Iterate each array anInputArray.forEach(item => { if (!isMaxed(item.id)) { summary.push({uid: item.id, type: item.type, count: item.count > maxValue ? 10 : item.count}) } }) }) return new Map(summary.map(obj => { return [obj.uid + '|' + obj.type, obj.count] })) } var arrayOfA = [ { "type": "A", "count": 10, "id": "UID1" }, { "type": "A", "count": 20, "id": "UID2" }, { "type": "A", "count": 1, "id": "UID4" }, ]; const arrayOfB = [ { "type": "B", "count": 5, "id": "UID1" }, { "type": "B", "count": 5, "id": "UID3" }, ]; var arrayOfC = [ { "type": "C", "count": 6, "id": "UID1" }, { "type": "C", "count": 6, "id": "UID4" }, { "type": "C", "count": 3, "id": "UID2" }, { "type": "C", "count": 3, "id": "UID3" }, ] var m = getIdSummary([arrayOfA, arrayOfB, arrayOfC]); console.log(Array.from(m)); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM