简体   繁体   English

Javascript-使用映射函数而不是嵌套的for循环反规范化JSON数组

[英]Javascript - denormalize JSON array using map function instead of nested for loop

I'm trying to get my head around map functions. 我正在努力使自己了解地图功能。 Here is my working code and output using a nested for loop: 这是我的工作代码,并使用嵌套的for循环输出:

var jsonsToAddTo = [
    {'cat':'k1','key2':'a'},
    {'cat':'k1','key2':'b'},
    {'cat':'k2','key2':'a'},
    {'cat':'k2','key2':'b'},
    {'cat':'k3','key2':'a'}
]

var additionalData = [
    {'pk':'k1','key3':'data1'},
    {'pk':'k2','key3':'data2'},
    {'pk':'k3','key3':'data3'},
]

// Adds a key value pair from sourceJson to targetJson based on a matching value
function denormalizeJsonOnKey(targetJsonArray,targetKeyToMatch, sourceJsonArray, sourceKeyToMatch, keyToAdd){
    for(thisJson in targetJsonArray){
        for(thatJson in sourceJsonArray){
            if(targetJsonArray[thisJson][targetKeyToMatch]==sourceJsonArray[thatJson][sourceKeyToMatch]){
                console.log('match');
                targetJsonArray[thisJson][keyToAdd]=sourceJsonArray[thatJson][keyToAdd];
            }
        }
    }
    return targetJsonArray
}

console.log(denormalizeJsonOnKey(jsonsToAddTo,'cat',additionalData,'pk','key3'))

OUTPUT: OUTPUT:

[ 
    { cat: 'k1', key2: 'a', key3: 'data1' },
    { cat: 'k1', key2: 'b', key3: 'data1' },
    { cat: 'k2', key2: 'a', key3: 'data2' },
    { cat: 'k2', key2: 'b', key3: 'data2' },
    { cat: 'k3', key2: 'a', key3: 'data3' } 
]

I can't figure out how to handle the nesting using a map function on an array. 我不知道如何使用数组上的map函数来处理嵌套。

Using ES6 can simplify using Array#find() and Object#assign() 使用ES6可以简化使用Array#find()Object#assign()

 var data = [ {'cat':'k1','key2':'a'}, {'cat':'k1','key2':'b'}, {'cat':'k2','key2':'a'}, {'cat':'k2','key2':'b'}, {'cat':'k3','key2':'a'} ] var data2 = [ {'pk':'k1','key3':'data1'}, {'pk':'k2','key3':'data2'}, {'pk':'k3','key3':'data3'}, ] const mergeData= (arr1, arr2, matchKey, filterKey, includeKey)=>{ arr1.forEach(o => { const newObj ={}; const match = arr2.find(e => e[filterKey] === o[matchKey]) newObj[includeKey] = match ? match[includeKey] : null; Object.assign(o, newObj); }); } mergeData(data, data2,'cat', 'pk', 'key3') console.log(data) 

Here is a solution that takes advantage of map and object spread to produce a new array with the desired key added into the target array's elements: 这是一个利用map和对象扩展来产生一个新数组的解决方案,该数组将所需的键添加到目标数组的元素中:

 var jsonsToAddTo = [ {'cat':'k1','key2':'a'}, {'cat':'k1','key2':'b'}, {'cat':'k2','key2':'a'}, {'cat':'k2','key2':'b'}, {'cat':'k3','key2':'a'} ] var additionalData = [ {'pk':'k1','key3':'data1'}, {'pk':'k2','key3':'data2'}, {'pk':'k3','key3':'data3'}, ] function denormalizeJsonOnKey(targetJsonArray,targetKeyToMatch, sourceJsonArray, sourceKeyToMatch, keyToAdd){ return targetJsonArray.map(thisJson => { const addObj = sourceJsonArray.find(thatJson => thatJson[sourceKeyToMatch] === thisJson[targetKeyToMatch]); return { ...thisJson, ...addObj ? {[keyToAdd]: addObj[keyToAdd]} : {}, } }); } console.log(denormalizeJsonOnKey(jsonsToAddTo, 'cat', additionalData, 'pk', 'key3')) 

Note that this solution won't mutate the original array, so the jsonsToAddTo variable will be the same after you invoke the function. 请注意,此解决方案不会jsonsToAddTo原始数组,因此调用该函数后, jsonsToAddTo变量将相同。 If you want to replace the original, you can always just re-assign it: 如果您想更换原件,可以随时重新分配它:

jsonsToAddTo = denormalizeJsonOnKey(jsonsToAddTo, 'cat', additionalData, 'pk', 'key3')
var targetJsonArray = jsonsToAddTo.map(function(json, index) {
    additionalData.forEach(function(data) {
        if (data.pk === json.cat) {
            json.key3 = data.key3;
        }
    })
    return json;
})

Try this, using maps for both iteration, 尝试使用maps进行两次迭代,

 var jsonsToAddTo = [{'cat':'k1','key2':'a'},{'cat':'k1','key2':'b'}, {'cat':'k2','key2':'a'},{'cat':'k2','key2':'b'}, {'cat':'k3','key2':'a'}] var additionalData = [{'pk':'k1','key3':'data1'},{'pk':'k2','key3':'data2'},{'pk':'k3','key3':'data3'}, ] function denormalizeJsonOnKey(targetJsonArray,targetKeyToMatch, sourceJsonArray, sourceKeyToMatch, keyToAdd){ jsonsToAddTo.map((obj,index)=> { additionalData.map((o,idx)=> { if(obj[targetKeyToMatch]==o[sourceKeyToMatch]){ obj[keyToAdd]=o[keyToAdd]; } }) }) return jsonsToAddTo } console.log(denormalizeJsonOnKey(jsonsToAddTo,'cat',additionalData,'pk','key3')) 

Rather than nesting loops here, which will iterate the entire additionalData array for every entry in jsonsToAddTo , I suggest building an object map of the additionalData dataset once at the beginning, and then reference this within a .map on the target dataset: 而不是在这里筑巢循环,这将遍历整个additionalData阵列中每个项目jsonsToAddTo ,我建议建立的一个对象映射additionalData开头数据集一次 ,然后对目标数据集.MAP中引用这样的:

var jsonsToAddTo = [
    {'cat':'k1','key2':'a'},
    {'cat':'k1','key2':'b'},
    {'cat':'k2','key2':'a'},
    {'cat':'k2','key2':'b'},
    {'cat':'k3','key2':'a'}
]

var additionalData = [
    {'pk':'k1','key3':'data1'},
    {'pk':'k2','key3':'data2'},
    {'pk':'k3','key3':'data3'},
]

// Adds a key value pair from sourceJson to targetJson based on a matching value
function denormalizeJsonOnKey(targetJsonArray,targetKeyToMatch, sourceJsonArray, sourceKeyToMatch, keyToAdd){
    // Build an object of items keyed on sourceKeyToMatch
    const sourceJsonMap = sourceJsonArray.reduce((obj, item) => (obj[item[sourceKeyToMatch]]=item, obj), {});
    return targetJsonArray.map(item => {
        const targetValue = item[targetKeyToMatch];
        if (sourceJsonMap.hasOwnProperty(targetValue)) {
        item[keyToAdd] = sourceJsonMap[targetValue][keyToAdd];
      }
      return item;
    });
}

console.log(denormalizeJsonOnKey(jsonsToAddTo,'cat',additionalData,'pk','key3'))

Doing it this way should be far more efficient, especially if the dataset you are working on is fairly large. 这样做的效率应该更高得多,尤其是当您正在处理的数据集相当大时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM