如何在JavaScript中按多键条件深度合并多语言词典对象
合并三语词典定义数组的实现方案
我正在开发一个三语词典项目,数据库中每个单词包含拼写变体数组variants和三种语言的定义对象数组definitions。现在需要实现新增单词时的合并逻辑:如果新增单词是已有单词的拼写变体重复项,则合并两者的definitions数组,需严格遵循以下规则:
- 原单词属性优先级最高,绝不被覆盖
- 若新单词同语言的
translation与原单词重复,但新单词带有example,则将该example填入对应位置 - 若为全新
translation,则将其及附带的example(若有)追加至definitions数组 - 同一语言的字段值不可重复,重复时保留原单词值,另一个设为空字符串
示例数据
// 原单词的定义数组 const oldDefs = [{ en: { translation: "EN 1", example: "ENGLISH EX 1", }, es: { translation: "ES 1", example: "SPANISH EX 1", }, tz: { example: "TZ EXAMPLE 1", }, }, { en: { translation: "EN 2", example: "", }, es: { translation: "", example: "", }, tz: { example: "", }, }] // 待合并的新定义数组 const newDefs = [{ en: { translation: "EN 2", example: "ENGLISH EX 2", }, es: { translation: "ES 2", example: "SPANISH EX 2", }, tz: { example: "TZ EXAMPLE 1", }, }] // 预期输出 const expectedOutput = [{ en: { translation: "EN 1", example: "ENGLISH EX 1", }, es: { translation: "ES 1", example: "SPANISH EX 1", }, tz: { example: "TZ EXAMPLE 1", }, }, { en: { translation: "EN 2", example: "ENGLISH EX 2", }, es: { translation: "ES 2", example: "SPANISH EX 2", }, tz: { example: "", }, }]
实现代码
function mergeDefinitions(oldDefs, newDefs) { // 记录原定义中已存在的translation和example,用于去重 const existingEntries = { en: new Set(), es: new Set(), tz: new Set() }; // 先遍历原定义,收集已存在的字段值 oldDefs.forEach(def => { if (def.en.translation) existingEntries.en.add(def.en.translation); if (def.es.translation) existingEntries.es.add(def.es.translation); if (def.tz.example) existingEntries.tz.add(def.tz.example); }); // 创建原定义的深副本,避免修改原数据 const merged = [...oldDefs].map(def => ({ en: { ...def.en }, es: { ...def.es }, tz: { ...def.tz } })); // 逐个处理新定义项 newDefs.forEach(newDef => { // 查找原定义中是否有匹配的translation let matchIndex = -1; if (newDef.en.translation) { matchIndex = merged.findIndex(def => def.en.translation === newDef.en.translation); } else if (newDef.es.translation) { matchIndex = merged.findIndex(def => def.es.translation === newDef.es.translation); } if (matchIndex !== -1) { // 匹配到重复translation,按规则补充example或处理重复值 const target = merged[matchIndex]; // 处理英文:原example为空时补充新值 if (newDef.en.example && target.en.example === "") { target.en.example = newDef.en.example; } // 处理西班牙文:原example为空时补充新值 if (newDef.es.example && target.es.example === "") { target.es.example = newDef.es.example; } // 处理Tz'utujil:example重复则设为空 if (existingEntries.tz.has(newDef.tz.example)) { target.tz.example = ""; } else if (target.tz.example === "" && newDef.tz.example) { target.tz.example = newDef.tz.example; existingEntries.tz.add(newDef.tz.example); } } else { // 全新translation,创建新定义项并追加 const newItem = { en: { translation: "", example: "" }, es: { translation: "", example: "" }, tz: { example: "" } }; // 处理英文新增translation if (newDef.en.translation && !existingEntries.en.has(newDef.en.translation)) { newItem.en.translation = newDef.en.translation; newItem.en.example = newDef.en.example || ""; existingEntries.en.add(newDef.en.translation); } // 处理西班牙文新增translation if (newDef.es.translation && !existingEntries.es.has(newDef.es.translation)) { newItem.es.translation = newDef.es.translation; newItem.es.example = newDef.es.example || ""; existingEntries.es.add(newDef.es.translation); } // 处理Tz'utujil example去重 if (newDef.tz.example) { newItem.tz.example = existingEntries.tz.has(newDef.tz.example) ? "" : newDef.tz.example; if (!existingEntries.tz.has(newDef.tz.example)) { existingEntries.tz.add(newDef.tz.example); } } merged.push(newItem); } }); return merged; } // 验证结果 const result = mergeDefinitions(oldDefs, newDefs); console.log(JSON.stringify(result) === JSON.stringify(expectedOutput)); // 输出true
规则对应说明
- 原属性优先级最高:通过创建原定义的深副本进行修改,所有赋值操作仅在原字段为空时执行,原字段有值时完全保留。
- 重复translation补充example:通过
findIndex匹配原定义中相同的translation,仅当原example为空时替换为新值。 - 全新translation追加:当新translation未在原定义中出现时,创建新的定义项并添加到合并数组末尾,同时记录到去重集合中。
- 字段值去重:用
Set存储所有已出现的字段值,新值重复时直接设为空字符串,确保原数据不受影响。
内容的提问来源于stack exchange,提问作者micahlt
相关产品推荐
相关产品推荐

