【问题标题】:How to match values between two objects and create new with specific values如何匹配两个对象之间的值并使用特定值创建新对象
【发布时间】:2016-03-17 14:00:07
【问题描述】:

我有对象数组 oDataSetaProperties 对象,我想匹配在 aPropertisoDataSet 中找到的 相同 值并创建 aSelectedDataSet 开始是一个空对象

如何在 JS/Jquery 中推荐

注意:循环/解决方案中不应有任何硬编码 属性来进行匹配 aProperties 包含此值,但可以更改(当然,oData 对象中应该有匹配项......)

为了澄清以下是如何构建对象的示例

http://jsfiddle.net/4rh6tt25/5/

这是输入

 //This is given array of object which can be many ,here I put just two instance in the array for demonstration purpose
var oDataSet = [{
    __metadata: {
        aaa: 111,
        bbb: 222
    },
    to_ExcludedTerms: {results: []},
    to_ListTypeGroupAssignment: {
        results: [
            {
                AuthorisationGroup: 'AuthorisationGroup 1',
                ListTypeGroup: 'ListTypeGroup1',
                ListTypeGroupDescription: 'ListTypeGroupDescription 1',
                ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 2',
                ListTypeGroup: 'ListTypeGroup2',
                ListTypeGroupDescription: 'ListTypeGroupDescription 2',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 3',
                ListTypeGroup: 'ListTypeGroup3',
                ListTypeGroupDescription: 'ListTypeGroupDescription 3',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
                __metadata: {}
            }
        ]
    }
}, {
    //This is the second instance of the object with same keys but different values
    __metadata: {
        aaa: 333,
        bbb: 444
    },
    to_ExcludedTerms: {results: []},
    to_ListTypeGroupAssignment: {
        results: [
            {
                AuthorisationGroup: 'AuthorisationGroup 6',
                ListTypeGroup: 'ListTypeGroup6',
                ListTypeGroupDescription: 'ListTypeGroupDescription 6',
                ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 7',
                ListTypeGroup: 'ListTypeGroup7',
                ListTypeGroupDescription: 'ListTypeGroupDescription 7',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 8',
                ListTypeGroup: 'ListTypeGroup8',
                ListTypeGroupDescription: 'ListTypeGroupDescription 8',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
                __metadata: {}
            }
        ]
    }
}
];

//This is the values which I should search find in oDataSet
//The to_ListTypeGroupAssignment or other property which under the same structure
//should be with the following path but under the results which is the only
//hardcoded property
var aProperties = [
    "to_ListTypeGroupAssignment/ListTypeGroup",
    "to_ListTypeGroupAssignment/ListTypeGroupDescription"
]

这是输出

这是应该从上面输入中的两个对象的合并构建的输出示例

var aSelectedDataSet = [
    {
        __metadata: {
            aaa: 111,
            bbb: 222
        },
        to_ListTypeGroupAssignment: {
            results: [
                {
                    ListTypeGroup: 'ListTypeGroup1',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 1'
                },
                {
                    ListTypeGroup: 'ListTypeGroup2',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 2',

                },
                {
                    ListTypeGroup: 'ListTypeGroup3',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 3',
                }
            ]
        }
    },
    {
        __metadata: {
            aaa: 333,
            bbb: 444
        },
        to_ListTypeGroupAssignment: {
            results: [
                {
                    ListTypeGroup: 'ListTypeGroup1',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 1'
                },
                {
                    ListTypeGroup: 'ListTypeGroup2',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 2',

                },
                {
                    ListTypeGroup: 'ListTypeGroup3',
                    ListTypeGroupDescription: 'ListTypeGroupDescription 3',
                }
            ]
        }
    }

]

只是为了从下面的 cmets 中澄清:) 唯一可以硬编码的是results不是任何属性名称,例如 ListTypeGroup& ListTypeGroupDescription 这应该是 generic 并从 aProperties 读取

你看 oData 的结构应该像下面这样

property(like -> to_ListTypeGroupAssignmen)
        results(hardcoded & mandatory in every exist object)
             properties(like ListTypeGroup& ListTypeGroupDescription with there values)

如果我需要更清楚,请告诉我如何,我应该添加哪些附加信息...这是在我尽可能更新问题之后...

【问题讨论】:

  • 你能用代码替换图像吗?人们尝试复制和粘贴代码并重建您的问题要容易得多,而不是从图像中读取它。见How to Ask
  • 学习编程的一部分就是自己编程。您如何尝试将相关问题应用到您自己的代码中,然后针对您在哪里遇到问题提出一个具体问题?
  • @MiltoxBeyond - 只有结果可以硬编码 :) 忘了提这个
  • @Frederik.L - 谢谢,但我认为你错过了这里的重点......大多数 cmets 都是针对我今天大幅更新并创建 JsFiddle 的原始问题,输出应该是我放的 aSelectedDataSet以及应该如何创建它的示例(使用值),此外,在小提琴的底部,您可以看到我尝试的内容,但没有成功:(
  • 很抱歉,但我必须坚持:你一直在问你需要什么,所以即使有善意,也没有人能真正理解它。你似乎总是很匆忙,这不是达到目标的好方法。因此,请花时间以清晰的方式重构您的问题!否则,您想要节省的时间实际上会浪费在您身上(因为您不会得到任何答案)......对我们来说也是如此!

标签: javascript jquery arrays recursion javascript-objects


【解决方案1】:

您可以使用这个递归的纯 JavaScript 函数:

下面的 sn-p 将此函数应用于您提供的示例数据并返回所需的结果:

function extract(data, select, curpath) {
    var result = {};
    // Part of the path that has been traversed to get to data:
    curpath = curpath || '';        
    if (typeof data !== 'object') { // data is a primitive (we assume)
        return data;
    } 
    if (typeof data.slice === 'function') { // data is an Array
        return data.map(function (el, idx) {
            return extract(el, select, curpath); // same path!
        });
    }
    // data is an Object:
    // The specific case of the "__metadata" property
    if (data.__metadata !== undefined && curpath.length === 0) {
        result.__metadata = data.__metadata;
    }
    // Core of this algorithm: take the relevant paths only...
    var subselect = select.filter(function(path) {
        return (path+'/').indexOf(curpath) == 0;
    });
    subselect.forEach(function (path, _, subselect) {
        // then get the next property in such path...
        var prop = path.substr(curpath.length).split('/')[0];
        // and check if we have that property on the current object:
        if (data[prop] !== undefined) {
            // If so, recurse while adding this to the current path:
            result[prop] = extract(data[prop], subselect, curpath+prop+'/');
        }
    });
    // The specific case of the "results" property
    if (data.results !== undefined) {  // recurse with same path!
        result.results = extract(data.results, select, curpath);
    }
    return result;
} 


// Test data
var oDataSet = [{
    __metadata: {
        aaa: 111,
        bbb: 222
    },
    to_ExcludedTerms: {results: []},
    to_ListTypeGroupAssignment: {
        results: [
            {
                AuthorisationGroup: 'AuthorisationGroup 1',
                ListTypeGroup: 'ListTypeGroup1',
                ListTypeGroupDescription: 'ListTypeGroupDescription 1',
                ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692111',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 2',
                ListTypeGroup: 'ListTypeGroup2',
                ListTypeGroupDescription: 'ListTypeGroupDescription 2',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 3',
                ListTypeGroup: 'ListTypeGroup3',
                ListTypeGroupDescription: 'ListTypeGroupDescription 3',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb5',
                __metadata: {}
            }
        ]
    }
}, {
    __metadata: {
        aaa: 333,
        bbb: 444
    },
    to_ExcludedTerms: {results: []},
    to_ListTypeGroupAssignment: {
        results: [
            {
                AuthorisationGroup: 'AuthorisationGroup 6',
                ListTypeGroup: 'ListTypeGroup6',
                ListTypeGroupDescription: 'ListTypeGroupDescription 6',
                ParentKey: '8ae25d47-c3cc-4ee3-a040-ea00505692116',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 7',
                ListTypeGroup: 'ListTypeGroup7',
                ListTypeGroupDescription: 'ListTypeGroupDescription 7',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb7',
                __metadata: {}
            },
            {
                AuthorisationGroup: 'AuthorisationGroup 8',
                ListTypeGroup: 'ListTypeGroup8',
                ListTypeGroupDescription: 'ListTypeGroupDescription 8',
                ParentKey: '34bcdc74-ab42-4538-8657-0a2b0473fcb8',
                __metadata: {}
            }
        ]
    }
}
];

var aProperties = [
    "to_ListTypeGroupAssignment/ListTypeGroup",
    "to_ListTypeGroupAssignment/ListTypeGroupDescription"
];
// (End of sample data)

// Call the function to get the result:
var aSelectedDataSet = extract(oDataSet, aProperties);

// For this snippet only: output the result in readable format
document.write('<pre>'+JSON.stringify(aSelectedDataSet, 0, 4)+'</pre>');

算法说明:

代码已注释。这就是算法的工作原理:

  • 该函数是递归的,并获取当前数据,一旦该函数被递归调用,当前数据将只是原始数据的一个子部分。
  • 该函数还采用路径样式属性进行选择。此外,这个列表会更短,因为函数是递归调用的,所以它只有那些仍然与数据部分相关的条目。
  • 第三个参数是已经走过的路径。在最初的调用中,这只是一个空字符串,但随着递归的开始,它会变成 'to_ListTypeGroupAssignment/',后来甚至变成 'to_ListTypeGroupAssignment/ListTypeGroup/'(总是带有终止斜杠)。
  • 函数的每次调用都将返回与(路径样式)选择匹配的给定数据的一部分。
  • 该函数首先识别数据的类型:它是原始值(字符串、数字、布尔值)还是数组(初始调用时的情况)或(非数组)对象。
  • 如果它是一个数组,该函数只是为每个元素递归调用,而不向路径添加任何内容。然后将每次调用的结果存储在一个数组中,该数组成为返回值。
  • 如果是原始值,则表示我们递归到“树”中的“叶子”。既然我们到了这里,我们可以假设“路径”一直匹配到这一点,因此必须返回原始值,以便将其添加到结果中
  • 如果它是一个对象,则遍历选择路径以查看这些路径中的下一级是否与当前数据的对象属性匹配。如果是这样,则该属性值通过递归调用传递,同时还将该路径添加到“当前”路径

__metadataresults显然有例外,在代码中分别处理。

【讨论】:

  • 这应该是 IMO 接受的答案。除非有其他例外?
【解决方案2】:

其中一个简短的解决方案是使用 lodash。它具有_.assignInWith(object, sources, [customizer]) 功能,使用它您将拥有以下功能:

var customizer = function(key) { return key in aPropertis }

var newSet = _.assignInWith({} , oDataSet, customizer)

但是,它仅适用于一级属性。

【讨论】:

  • 对不起,我不能使用 lodash。
  • 在我们的项目中,我们不能使用 lodash 或 undercore :(
  • 请问为什么?没有它你们怎么工作。
  • 我知道有非常好的但是在我们的项目中我们现在不能(合法等)使用 lodash 但将来我们会......
【解决方案3】:

不是最优雅的方式,但很有效。

JSFiddle Link

比较嵌套结构并删除不需要的键。

限制:
1.__metadata是硬编码
2.results是硬编码的

您想要的输出与生成的不同,区别在于 你的输出:

aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 1

而在生成的输出中是:

aSelectedDataSet[2].to_ListTypeGroupAssignment.results[1].ListTypeGroupDescription === 6

我认为,这是您的问题中的一个错字。

代码:

var convertPropertyRelation = function(propertiesArray) {
  if (!Array.isArray(propertiesArray))
    return [];
  var formattedProperties = {},
    i, len = propertiesArray.length,
    currentRelation;
  for (i = 0; i < len; i++) {

    currentRelation = propertiesArray[i].split('/');

    if (formattedProperties.hasOwnProperty(currentRelation[0])) {
      formattedProperties[currentRelation[0]].push(currentRelation[1]);
    } else {
      formattedProperties[currentRelation[0]] = [currentRelation[1]];
    }

  }
  return formattedProperties;
};

var generateDataSet = function() {
  var formattedProperties = convertPropertyRelation(aProperties),
    firstRelation = Object.keys(formattedProperties),
    i, len = firstRelation.length,
    j, resultArray, resultLength;

  var dataSet = oDataSet.map(function(dataSetObject) {
    for (var firstKey in dataSetObject) {

      if (firstKey === '__metadata') {

        continue;

      } else if (firstRelation.indexOf(firstKey) === -1) {

        delete dataSetObject[firstKey];

      } else {

        // if first relation is present
        if (dataSetObject.hasOwnProperty(firstKey)) {
          // results array in the firstRelation
          resultArray = dataSetObject[firstKey].results;
          // for all results
          for (j = 0, resultLength = resultArray.length; j < resultLength; j++) {
            // for all keys in current result
            for (var respectiveKey in resultArray[j]) {
              // if the key is present leave it as it is
              if (formattedProperties[firstKey].indexOf(respectiveKey) === -1) {
                delete resultArray[j][respectiveKey];
              }
            }

          }

        }

      }

    }
    return dataSetObject;
  });

  return dataSet;
};

【讨论】:

  • 请在您的答案中发布代码本身,而不是指向它的链接。
  • @Bergi 我已经添加了代码,但是 Trincot 添加的答案更优雅更好
【解决方案4】:

您必须将 oDataSet 的每个属性与 aSelectedDataSet 的每个属性进行比较

var res=[];
for (var key1 in oDataSet){
 for(var key2 in aSelectedDataSet ){
   if(key1==key2){
    res[key1]=oDataSet[key1];
   }
 }
}

编辑:

如果你这样定义过滤器

var filter={
    __metadata:'',
    to_ListTypeGroupAssignment:{
        results:[{
            ListTypeGroup:'',
            ListTypeGroupDescription:''
        }]
    }

}

并通过递归将其应用于数据

function recursiveValue(filter,data){
    var res={};
    for(var key in filter){
        var val=data[key];
        var p=filter[key];
        if(val==='undefined') continue; 
        if(p===''){
            res[key] = val;
        }else if(Array.isArray(p)){
            var tmp = [];
            for(var i=0;i<val.length;i++){
                tmp.push(recursiveValue(filter[key][0],val[i]));
            }
            res[key] = tmp;
        }else if(typeof p=='object'){
            res[key] = recursiveValue(filter[key],val);
        }
    }
    return res;
}

像这样

var results=[];
for(var i=0;i<oDataSet.length;i++){
    results.push(recursiveValue(filter,oDataSet[i]));
}

你得到

console.log(results);

【讨论】:

  • 我试过了,但它不起作用,你能使用我提供的jsFiddle吗?您没有参考结果属性,请使用代码,我提供确切的输出...
  • 您的代码将不起作用(它不是那么简单......)因为 aSelectedDataSet 只是一个 var 并且在匹配后它应该被填充它是空的(就像问题中的输出......)
【解决方案5】:

您可以使用 ES5 提供的函数式编程技术来解决这个问题。试试这个小提琴:https://jsfiddle.net/yh39of1b/3/

var aProperties = [
     "to_ListTypeGroupAssignment/ListTypeGroup",
     "to_ListTypeGroupAssignment/ListTypeGroupDescription"
];

//maps the properties you wish to capture
var propertyList = aProperties.map(function(properties) {
   return properties.split('/');
});

//reduces the oData array to the data you require
aSelectedDataSet = oData.reduce(function(existing,current){
     var obj = {};

     //each iteration of oData goes through each property group
     //first at the parent property level
     propertyList.forEach(function(property){
       if (typeof obj[property[0]] === 'undefined') {
        obj[property[0]] = {};
        obj[property[0]].results = [];
       }

       if(current[property[0]]) {
           //now at the child property level
           current[property[0]].results.forEach(function(result,index){
                 if(typeof obj[property[0]].results[index] === 'undefined')
                     obj[property[0]].results[index] = {};

                 obj[property[0]].results[index][property[1]] = result[property[1]];
           });
       }

   });
   //add the newly mapped object to the aSelectedDataSet array
   existing.push(obj);
   return existing;
},[]);

【讨论】:

    猜你喜欢
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 2018-07-13
    • 2018-05-18
    • 1970-01-01
    相关资源
    最近更新 更多