如何高效合并具有相同account和page属性值的对象数组?
account and page with Array Conversion for Duplicate Properties Great question! Let's break down a clean, high-performance solution that meets all your requirements—including handling duplicate object properties by converting them to arrays, and avoiding inefficient nested loops.
Core Approach: Use a Map for O(n) Time Complexity
Instead of nested loops (which hit O(n²) time), we'll use a Map to track grouped objects as we iterate through the input array once. This gives us O(n) overall time complexity, since map lookups are O(1) operations. Here's how it works:
- Generate a unique key for each object using its
accountandpagevalues (e.g.,account-page). - For each object in the array:
- If the key doesn't exist in the map, add the object as-is.
- If the key exists, merge properties:
- For non-object properties (like
amount), keep the initial value (you can adjust this to override if needed). - For object properties (like
items), convert existing values to an array if a duplicate is found, then append the new object.
- For non-object properties (like
Full Code Implementation
function mergeObjectsByAccountAndPage(arr) { const groupedObjects = new Map(); arr.forEach(obj => { // Create a unique identifier for the account-page pair const groupKey = `${obj.account}-${obj.page}`; const existingObj = groupedObjects.get(groupKey); if (!existingObj) { // No existing entry—add a copy of the current object to the map groupedObjects.set(groupKey, {...obj}); return; } // Merge properties with the existing entry Object.entries(obj).forEach(([propName, propValue]) => { if (existingObj[propName]) { // Property already exists—handle object types specially if (typeof propValue === 'object' && propValue !== null) { if (Array.isArray(existingObj[propName])) { // Already an array—push the new object existingObj[propName].push(propValue); } else { // Convert existing object to array and add the new value existingObj[propName] = [existingObj[propName], propValue]; } } // For non-object properties, we keep the initial value (uncomment below to override) // existingObj[propName] = propValue; } else { // Property doesn't exist—add it to the existing object existingObj[propName] = propValue; } }); }); // Convert map values back to a regular array return Array.from(groupedObjects.values()); } // Test with your initial data let data = [ {account: 1, page: 1, amount: 123}, {account: 1, page: 1, items: {desc: 'test', date: '12/31/2021'}}, {account: 1, page: 2, amount: 789}, {account: 2, page: 1, amount: 456} ]; console.log(mergeObjectsByAccountAndPage(data)); // Output matches your first expected result // Test with the new duplicate object added data.push({account: 1, page: 1, items: {desc: 'another one', date: '8/2/2021'}}); console.log(mergeObjectsByAccountAndPage(data)); // Output matches your second expected result
What About Lodash's merge?
Unfortunately, lodash's merge method isn't a direct fit here. merge recursively combines object properties, but it will overwrite nested values instead of converting duplicate object properties into arrays. For example, merging two objects with an items property would merge their desc/date fields (overwriting conflicts) rather than creating an array of items objects.
You could combine lodash utilities like groupBy and mergeWith to replicate this behavior, but the custom implementation above is more straightforward and avoids adding a dependency if you don't already use lodash.
Key Advantages
- Efficiency: Runs in O(n) time, making it ideal for large datasets.
- Flexibility: Easily adjust behavior (e.g., override non-object properties instead of keeping the first value).
- Scalability: Works seamlessly with any length of input array.
内容的提问来源于stack exchange,提问作者Cineno28

