如何高效合并两个数组并为第二个数组的重复名称添加递增后缀(JavaScript ES6实现)
I have two arrays:
const array1 = [{name: "Darin", id: "123"}, {name: "Mads", id: "345"}, {name: "Kenneth", id: "543"}, {name: "June", id: "567"}, {name: "June (1)", id: "789"}]; const array2 = [{name: "Darin", id: "910"}, {name: "June", id: "911"}, {name: "Simon", id: "912"}, {name: "Justin", id: "913"}];
I want the merged result to look like this:
[{name: "Darin", id: "123"}, {name: "Mads", id: "345"}, {name: "Kenneth", id: "543"}, {name: "June", id: "567"}, {name: "June (1)", id: "789"}, {name: "Darin (1)", id: "910"}, {name: "June (2)", id: "911"}, {name: "Simon", id: "912"}, {name: "Justin", id: "913"}]
Key Rules:
- Only elements from Array 2 can get
(number)suffixes added. - For duplicate names, increment the suffix number until the name is unique in the merged array.
I know I could hack this together with nested loops and recursion, but that feels messy and inefficient. I want to leverage ES6 features like Map or Set to optimize the time complexity—any ideas on how to approach this?
Great question! Using a Map is perfect here because it lets us track name counts in constant time, which keeps the overall solution running in O(n + m) time (where n is the length of Array 1, m is Array 2)—way better than brute-force nested loops.
Here's a step-by-step breakdown and implementation:
Step 1: Parse Existing Names
First, we need a helper function to extract the "base name" and any existing suffix number from a name string. For example, June (1) becomes a base of June with a number of 1, while Darin has a base of Darin and number 0.
Step 2: Build a Count Map from Array 1
We'll iterate through Array 1 to figure out the highest suffix number used for each base name. This tells us what the next available suffix should be when we process Array 2.
Step 3: Process Array 2 and Merge
For each element in Array 2, we check the count map to get the next available suffix, generate the unique name, update the map, and add the element to our merged array.
Full Code Implementation
const array1 = [{name: "Darin", id: "123"}, {name: "Mads", id: "345"}, {name: "Kenneth", id: "543"}, {name: "June", id: "567"}, {name: "June (1)", id: "789"}]; const array2 = [{name: "Darin", id: "910"}, {name: "June", id: "911"}, {name: "Simon", id: "912"}, {name: "Justin", id: "913"}]; // Helper to split name into base and suffix number const parseName = (name) => { const match = name.match(/^(.*?)(?: \((\d+)\))?$/); return { base: match[1], number: match[2] ? parseInt(match[2], 10) : 0 }; }; // Initialize count map with data from array1 const nameCounter = new Map(); array1.forEach(item => { const { base, number } = parseName(item.name); // Keep track of the highest used suffix + 1 (next available) const currentMax = nameCounter.get(base) || 0; nameCounter.set(base, Math.max(currentMax, number + 1)); }); // Merge array1 and processed array2 const mergedArray = [...array1]; array2.forEach(item => { const { base } = parseName(item.name); const nextSuffix = nameCounter.get(base) || 0; const uniqueName = nextSuffix === 0 ? base : `${base} (${nextSuffix})`; mergedArray.push({ ...item, name: uniqueName }); // Update counter for future duplicates nameCounter.set(base, nextSuffix + 1); }); console.log(mergedArray);
How This Works:
parseName: The regex safely handles both names with and without suffixes, giving us the base name and numeric suffix (if present).nameCounterMap: For Array 1, we calculate the next available suffix for each base name. For example,Junehas entriesJuneandJune (1), so the next suffix is2.- Processing Array 2: When we hit
Darinin Array 2, the counter tells us the next suffix is1, so we rename it toDarin (1). Then we increment the counter so if anotherDarincomes in, it gets(2).
This approach is clean, efficient, and avoids the messy loops you were worried about. It also scales well even with larger arrays!
内容的提问来源于stack exchange,提问作者Jeppe Christensen

