使用Lodash高效合并相同subsets的JavaScript数组对象
Let's cut to the chase—your current Lodash-based approach works, but it's not the most efficient when dealing with large datasets. The core issue is that uniqueBy plus subsequent grouping adds extra overhead. Instead, we can use a plain JavaScript lookup object to do this in a single pass, which is way faster (O(n) time complexity vs. the O(n log n) or worse of your original method).
First, let's recap what we're working with:
Input
const originalFonts = [ { subsets: [ { start: '0020', end: '007F' }, { start: '0020', end: '007G' }, { start: '0020', end: '007G' } ], fontFormat: 'woff2', src: 'estPath1/' }, { subsets: [ { start: '0020', end: '007F' }, { start: '0020', end: '007G' }, { start: '0020', end: '007G' } ], fontFormat: 'woff', src: 'estPath2/' } ];
Desired Output
[ { subset: [ { start: '0020', end: '007F' }, { start: '0020', end: '007G' }, { start: '0020', end: '007G' } ], webFontList: [ { fontFormat: 'woff2', src: 'estPath1/' }, { fontFormat: 'woff', src: 'estPath2/' } ] } ]
The Efficient One-Pass Solution
Here's how to do it with vanilla JS, no external libraries:
function mergeFontsBySubset(fonts) { const subsetMap = {}; const result = []; for (const font of fonts) { // Create a unique key for the subsets array // JSON.stringify works here because the subset objects have consistent order/structure const subsetKey = JSON.stringify(font.subsets); if (subsetMap[subsetKey]) { // We've seen this subset before—add the font to the webFontList subsetMap[subsetKey].webFontList.push({ fontFormat: font.fontFormat, src: font.src }); } else { // New subset—create a new entry and add it to our map and result array const newEntry = { subset: [...font.subsets], // Optional: deep clone if you want to avoid reference issues webFontList: [{ fontFormat: font.fontFormat, src: font.src }] }; subsetMap[subsetKey] = newEntry; result.push(newEntry); } } return result; } // Usage const mergedFonts = mergeFontsBySubset(originalFonts); console.log(mergedFonts);
Why This Is Better
- Single pass: We only iterate over the original array once, instead of first deduplicating then grouping.
- O(1) lookups: The object-based map lets us check if a subset exists instantly, no looping through a deduplicated list every time.
- No external dependencies: You don't need Lodash anymore, which reduces bundle size if that's a concern.
Edge Case Note
If your subsets arrays might have the same objects but in a different order, JSON.stringify will treat them as different keys. To fix that, you can sort the subsets first (or sort the keys within each subset object) before stringifying. For example:
// Helper to create a consistent key even if subset order varies function getSubsetKey(subsets) { // First sort the subsets by start/end, then stringify const sortedSubsets = [...subsets].sort((a, b) => { if (a.start !== b.start) return a.start.localeCompare(b.start); return a.end.localeCompare(b.end); }); // Also ensure object keys are ordered (not necessary in modern JS, but safe) return JSON.stringify(sortedSubsets.map(subset => ({start: subset.start, end: subset.end}))); }
Then replace JSON.stringify(font.subsets) with getSubsetKey(font.subsets) in the function.
内容的提问来源于stack exchange,提问作者iAviator

