2

I want to run through two different List<SObject> lists in Javascript and count the number of times each list has an attribute that's the same across both lists (namely, a User Id).

Ex:

let hasBothCount = 0;
for (const upl of this.allUserPackageLicenses) {
    for (const psa of this.allPermissionSetAssignments) {
        if (upl.UserId === psa.AssigneeId) hasBothCount++;
    }
}
this.psaToLicenseCount = hasBothCount;

Is there a better / more efficient way to do this in Modern Javascript?

  • 1
    this would better be suited on stackoverflow, as it is not related to salesforce – glls Feb 25 at 22:33
  • I mostly agree. I posted here because 1) I'm just used to doing everything on SFSE and 2) I just thought others might have a similar question working with SObject records from Apex methods into their LWCs, so didn't think it was totally unrelated :shrug: – Brian Miller Feb 25 at 23:29
  • 1
    I agree that others might have similar if not the same question, but the fact remains that it is unrelated, even-though lwc and apex are mentioned. Glad someone answered you though =) - we are after all, helping each other out here. – glls Feb 26 at 0:30
6

You can do this far more efficiently using something like:

let hasUserId = {};
let hasBothCount = 0;

allUserPackageLicenses.forEach(upl => {
    hasUserId[upl.UserId] = 1;
});

allPermissionSetAssignments.forEach(psa => {
    if (hasUserId[psa.AssigneeId]) {
        hasBothCount++;
    }
});
  • Technically, you should start with 0, not 1, though, because you're only interested in rows with at least one match in each? Not a bad solution overall. – sfdcfox Feb 25 at 21:51
  • I should probably not call it counts; then there's no confusion :D – Phil W Feb 25 at 21:52
  • Is there any real difference between allUserPackageLicenses.forEach(upl => { and for (const upl of this.allUserPackageLicenses) {, besides the first looks more classically like JS and the second looks more declarative? I know for of is a newer JS construct but not sure how the performance would look – Brian Miller Feb 25 at 21:52
  • 1
    I think "for of" just lets you iterate more types of interable object, not just arrays. For example, IIRC, forEach can't be used directly on a NodeSet, but "for of" can. I don't know if there are any performance differences - but you can easily find out :) – Phil W Feb 25 at 21:57
6

Sure, here you go:

const assignedIds = this.allPermissionSetAssignments.map(psa => psa.AssigneeId);
const intersectionArray = this.allUserPackageLicenses.filter(upl => 
  assignedIds.includes(upl.UserId));
this.psaToLicenseCount = intersectionArray.length;

Adapted from this answer: https://stackoverflow.com/questions/1885557/simplest-code-for-array-intersection-in-javascript

  • 2
    I tested this with 10000 package licenses and 20000 permission set assignments and this took about 152ms. My solution, below, for the same data took 2ms. Just saying ;) – Phil W Feb 25 at 21:26
  • 1
    Fair enough, I must admit that I haven't tested perf for this. – POZ Feb 25 at 21:31
  • 1
    Both approaches work, of course. So Brian has the benefit of two different solutions :) – Phil W Feb 25 at 21:31

Not the answer you're looking for? Browse other questions tagged or ask your own question.