Get most matched Classes

const intersection = yourArray.filter(item1 => yourOtherArray.some(item2 => item2 === item1))
25 Replies
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Mana
ManaOP3y ago
You're doing == comparison on the entire array rather than its elements. Filtering array == arrayItem is never going to work right there.
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Mana
ManaOP3y ago
const icons = assignIcons
.filter(ai => ai.classList.some(i => elemClassList.includes(i)))
.map(ai => ({icons: ai, count: elemClassList.filter(i1 => ai.classList.some(i2 => i2 == i1)).length}))
.sort((a,b) => sortByTheNewCountHere);
const icons = assignIcons
.filter(ai => ai.classList.some(i => elemClassList.includes(i)))
.map(ai => ({icons: ai, count: elemClassList.filter(i1 => ai.classList.some(i2 => i2 == i1)).length}))
.sort((a,b) => sortByTheNewCountHere);
Something like that. It should then have the most matching item as the first item in the array.
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
so if you want the most matched classes not ALL matches this'll do:
// Turn elem.classList into a set so that `has` can be used which is a O(log(n)) operation compared to `includes` which is O(n)
const elemClassList = new Set(elem.classList);

const iconAndMatchCount = icons.map(icon => [
icon,
icon.classList.map(iconClass => iconClass.trim()).filter(iconClass => elemClassList.has(iconClass)).length // The number of matches
]);

const mostMatched = iconAndMatchCount.sort(([_a, aMatchCount], [_b, bMatchCount]) => bMatchCount - aMatchCount)[0][0];
// Turn elem.classList into a set so that `has` can be used which is a O(log(n)) operation compared to `includes` which is O(n)
const elemClassList = new Set(elem.classList);

const iconAndMatchCount = icons.map(icon => [
icon,
icon.classList.map(iconClass => iconClass.trim()).filter(iconClass => elemClassList.has(iconClass)).length // The number of matches
]);

const mostMatched = iconAndMatchCount.sort(([_a, aMatchCount], [_b, bMatchCount]) => bMatchCount - aMatchCount)[0][0];
the thing is that doesn't match the code you actually have I know you already got an answer I just wanted to add this way since there's some more efficiency there and this strictly speaking answers the initial question.
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
Honestly for small arrays you should see no difference Also doesn’t check every You can do this in O(n) time though
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
The thing with filter, map etc. is that they loop over the whole array and make a new one, e.g. for something like a.map(item => item + 1).map(item => item + 1).map(item => item + 1) it's gonna make several arrays some browsers will optimise things but there's no guarantees some languages have guarantees that these stream but that's besides the point
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
I'd only worry though for like arrays >1k size and also profile because browsers know they create new arrays, technically, but might optimise them away might you can do it like this if you want to get the result in one iteration of the array and minimal allocation:
const elemClassListSet = new Set(elemClassList);
let bestMatch;

for (const icon of icons) {
// Length is really fast to check as it's just metadata of the array. If we aren't a longer length than the current best match or longer length than the elemClassList there's no point to check matches at all because it can't possibly be the best match.
if (icon.classList.length < bestMatch?.classList.length || icon.classList.length < elemClassList.length) {
continue;
}

// We assume no duplicates in the icon's classList for efficiency. If we can't assume this we need to do better than just counting the match count as a duplicate would count as a match more than once.
let matchCount = 0;
for (const iconClass of icon.classList) {
// Because we're using a set checking to see if elemClassListSet has iconClass is an O(1) operation or constant time, instead of O(n) or requiring up to n checks in the array
if (elemClassListSet.has(iconClass)) {
matchCount += 1;
}
}

// We don't have at least one element in the elemClassList
if (matchCount < elemClassList.length) {
continue;
}

// This must be the new best match as it has a longer length and has every match in elem class list
bestMatch = icon;
}
const elemClassListSet = new Set(elemClassList);
let bestMatch;

for (const icon of icons) {
// Length is really fast to check as it's just metadata of the array. If we aren't a longer length than the current best match or longer length than the elemClassList there's no point to check matches at all because it can't possibly be the best match.
if (icon.classList.length < bestMatch?.classList.length || icon.classList.length < elemClassList.length) {
continue;
}

// We assume no duplicates in the icon's classList for efficiency. If we can't assume this we need to do better than just counting the match count as a duplicate would count as a match more than once.
let matchCount = 0;
for (const iconClass of icon.classList) {
// Because we're using a set checking to see if elemClassListSet has iconClass is an O(1) operation or constant time, instead of O(n) or requiring up to n checks in the array
if (elemClassListSet.has(iconClass)) {
matchCount += 1;
}
}

// We don't have at least one element in the elemClassList
if (matchCount < elemClassList.length) {
continue;
}

// This must be the new best match as it has a longer length and has every match in elem class list
bestMatch = icon;
}
but as you can probably tell that's not awfully readable and matchCount being, well, a count does assume no duplicates etc., i.e. if "window-app" shows up 3 times it'll throw off the match count code but this way you're guaranteed only one iteration of icons. I wouldn't really worry about actually using this though. Because the key insight in my opinion is frankly that this code is less readable and understandable at a glance. iterating an array of size like 1 million shouldn't even take a second too soooo yeah *correctness not guaranteed as I typed this out without actually running it
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
Gotcha sorry I mistook something you said as a correction I thought an item had to match everything in elemClassList
const elemClassListSet = new Set(elemClassList);
let bestMatch;
let bestMatchCount;

for (const icon of icons) {
const worseCount = icon.classList.length < bestMatch?.classList.length;

// if the best match has every match then we can ignore this one if the length is less.
if (bestMatchCount !== elemClassList.length && worseCount ) {
continue;
}

// We assume no duplicates in the icon's classList for efficiency. If we can't assume this we need to do better than just counting the match count as a duplicate would count as a match more than once.
let matchCount = 0;
for (const iconClass of icon.classList) {
// Because we're using a set checking to see if elemClassListSet has iconClass is an O(1) operation or constant time, instead of O(n) or requiring up to n checks in the array
if (elemClassListSet.has(iconClass)) {
matchCount += 1;
}
}

// We don't beat their number of matches so skip this
if (matchCount < bestMatchCount || worseCount) {
continue;
}

// This must be the new best match
bestMatch = icon;
}
const elemClassListSet = new Set(elemClassList);
let bestMatch;
let bestMatchCount;

for (const icon of icons) {
const worseCount = icon.classList.length < bestMatch?.classList.length;

// if the best match has every match then we can ignore this one if the length is less.
if (bestMatchCount !== elemClassList.length && worseCount ) {
continue;
}

// We assume no duplicates in the icon's classList for efficiency. If we can't assume this we need to do better than just counting the match count as a duplicate would count as a match more than once.
let matchCount = 0;
for (const iconClass of icon.classList) {
// Because we're using a set checking to see if elemClassListSet has iconClass is an O(1) operation or constant time, instead of O(n) or requiring up to n checks in the array
if (elemClassListSet.has(iconClass)) {
matchCount += 1;
}
}

// We don't beat their number of matches so skip this
if (matchCount < bestMatchCount || worseCount) {
continue;
}

// This must be the new best match
bestMatch = icon;
}
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
right, why are more classes better? Why not combine every class I suppose is what I'm saying. that may have obvious flaws but I'm asking mostly because if things are vague the user can only pick with like "actor" how do you know they want "actor", "npc" and not "actor", "vehicle" or just "actor" the code I gave will pick "actor", "npc" because it favors first and foremost the most matches, then the most classes, and then earlier ones in the array but a user may favor any of those 3, right?
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
it's totally fine if this code makes an intuitive UI I was just trying to make sure that I couldn't reveal any other strategies
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
Ah well since you doubt people'll use it too much why don't you come back if you find out people are using it lots
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
LukeAbby
LukeAbby3y ago
Ah nice seems convenient potentially I wouldn’t worry too much about the UX of customizing what seems to be a relatively niche configuration but I see the desire to find the one with most matched classes now
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Mana
ManaOP3y ago
Add a tour.
Unknown User
Unknown User3y ago
Message Not Public
Sign In & Join Server To View
Want results from more Discord servers?
Add your server