繁体   English   中英

如何使用javascript或lodash从对象数组中删除不匹配的对象

[英]How to remove unmatched objects from array of objects using javascript or lodash

我从服务器获取两个对象数组,如下所示:

var duplicateTestData = [
    { 
        licenseId: 'xxx',
        batchId: '123',
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time) 
    },
    { 
        licenseId: 'yyy',
        batchId: '124',
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time) 
    },
    { 
        licenseId: 'aaa',
        batchId: '145',
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time) 
    }
];

var finalResult = [
    { 
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time),
        license: {},
        testType: 'P1',
        productType: 'Flower',
        batchId: '123',
        licenseId: 'xxx',
        createType: 'DataUpload' 
    },
    { 
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time),
        testType: 'P1',
        productType: 'Flower',
        batchId: '124',
        licenseId: 'yyy',
        createType: 'DataUpload' 
    },
    { 
        reportDate: Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time),
        testType: 'P1',
        productType: 'Flower',
        batchId: '145',
        licenseId: 'aaa',
        createType: 'DataUpload' 
    },
    { 
        reportDate: Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time),
        testType: 'P1',
        productType: 'Flower',
        batchId: '145',
        licenseId: 'zzz',
        createType: 'DataUpload' 
    }
]

我试图从finalResult对象中只获取不匹配的对象,最终结果如下:

[
    { 
        reportDate: Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time),
        testType: 'P1',
        productType: 'Flower',
        batchId: '145',
        licenseId: 'zzz',
        createType: 'DataUpload' 
    } 
]  

我正在尝试这个,但没有得到正确的结果:

for(var j=0;j < duplicateTestData.length;j++){
    for (var i = 0; i < finalResult.length; i++) {
        if (
            (finalResult[i].licenseId == duplicateTestData[j].licenseId)  && 
            (finalResult[i].reportDate == duplicateTestData[j].reportDate) &&
            (finalResult[i].batchId == duplicateTestData[j].batchId)
        ) {
            finalResult.splice(i, 1);
            break;
        }
    }
}

console.log(finalResult);

简单的出路

finalResult.filter(({batchId:a, licenseId:b, reportDate:c}) =>
  duplicateTestData.find(({batchId:x, licenseId:y, reportDate:z}) =>
    a === x && b === y && c === z) === undefined)

=> [ { reportDate: 'Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time)',
    testType: 'P1',
    productType: 'Flower',
    batchId: '145',
    licenseId: 'zzz',
    createType: 'DataUpload' } ]

好的, 它有效 ,但这主要是垃圾。 它没有完全准确地描述您正在尝试进行的比较。 它太具体了,一旦你的数据发生变化就会中断。

继续阅读,我们可以学到一些有趣的东西


所有对象相等(键和值)...

我将首先制作几个通用程序,以便更好地描述我们问题的解决方案。

与其他解决方案相比,您对此解决方案的注意事项是,它不会对数据的内部结构做出任何假设。 此解决方案可能不关心对象中使用的实际键名称。

这意味着我们不会接触任何batchIdlicenseIdreportDate 在这种情况下,通用程序可以解决所有问题,最好的部分是你可以反复使用它们来处理你想要处理的任何数据。

 // arrayCompare :: (a -> b -> Bool) -> [a] -> [b] -> Bool const arrayCompare = f=> ([x,...xs])=> ([y,...ys])=> { if (x === undefined && y === undefined) return true else if (! f (x) (y)) return false else return arrayCompare (f) (xs) (ys) } // keys :: Object(k:v) -> [k] const keys = Object.keys // objectCompare :: (v -> v -> Bool) -> Object(k:v) -> Object(k:v) -> Bool const objectCompare = f=> a=> b=> arrayCompare (x=> y=> f (a[x]) (b[y]) && f (a[y]) (b[y])) (keys(a)) (keys(b)) // objectEqual :: Object -> Object -> Bool const objectEqual = objectCompare (x=> y=> x === y) // sample data let xs = [ {a:1,b:10}, {a:2,b:20}, {a:3,b:30} ] let ys = [ {a:1,b:10}, {a:2,b:20}, {a:3,b:30}, {a:4,b:40} ] // return all ys that are not present in xs var result = ys.filter(y=> xs.find(objectEqual(y)) === undefined) console.log(result) // [{a:4,b:40}] 

陷阱!

您必须稍微调整此解决方案,因为您没有比较所有对象键。 finalResult对象比duplicateTestData对象具有更多的键,因此没有1:1的匹配。

简单来说,如果将x = {a:1}y = {a:1,b:2}进行比较,则需要将x = {a:1}视为“匹配”,只要x中的所有键:值与所有键匹配: y

如果我们使用objectEquals上述比较,没有什么会被过滤掉的finalResult因为没有对象将匹配找到对象duplicateTestData 由于这不是你想要的,让我们定义一个适用于你的情况的比较器......

// subsetObjectEquals :: Object -> Object -> Bool
const subsetObjectEquals = objectCompare (x=> y=> y === undefined || x === y)

// this time use subsetObjectEquals
var result = finalResult.filter(x=>
  duplicateTestData.find(subsetObjectEquals(x)) === undefined)

subsetObjectEquals工作方式subsetObjectEquals不同。 我真的没想到一个更好的名字,因为这是一个有点奇怪的比较。 y undefined ,表示该值的键不存在于“子对象”中,因此不需要进行比较

subsetObjectEquals(a,b)
// returns true if all key:value pairs in `a` match all key:value pairs in `b`
// otherwise returns false

完整的工作范例

我附上了一个完整的片段,它实际上使用了你问题中包含的输入数据。 在此处展开​​并运行它以查看它是否有效

 // arrayCompare :: (a -> b -> Bool) -> [a] -> [b] -> Bool const arrayCompare = f=> ([x,...xs])=> ([y,...ys])=> { if (x === undefined && y === undefined) return true else if (! f (x) (y)) return false else return arrayCompare (f) (xs) (ys) } // keys :: Object(k:v) -> [k] const keys = Object.keys // objectCompare :: (v -> v -> Bool) -> Object(k:v) -> Object(k:v) -> Bool const objectCompare = f=> a=> b=> arrayCompare (x=> y=> f (a[x]) (b[x]) && f (a[y]) (b[y])) (keys(a)) (keys(b)) // objectEqual :: Object -> Object -> Bool const objectEqual = objectCompare (x=> y=> x === y) // subsetObjectEquals :: Object -> Object -> Bool const subsetObjectEquals = objectCompare (x=> y=> y === undefined || x === y) // your data var duplicateTestData = [{ licenseId: 'xxx', batchId: '123', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'yyy', batchId: '124', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'aaa', batchId: '145', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' } ]; var finalResult = [ { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', license: {}, testType: 'P1', productType: 'Flower', batchId: '123', licenseId: 'xxx', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '124', licenseId: 'yyy', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'aaa', createType: 'DataUpload' }, { reportDate: 'Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'zzz', createType: 'DataUpload' } ] // get all finalResult items that do not subsetObjectEqual items in duplicateTestData var result = finalResult.filter(x=> duplicateTestData.find(subsetObjectEquals(x)) === undefined) console.log(result) 

var res = _.filter(finalResult, function(item) {
  return !_.find(duplicateTestData, {
    batchId: item.batchId,
    licenseId: item.licenseId,
    reportDate: item.reportDate
  });
});
console.log(res);

的jsfiddle

您可以使用哈希表并返回一个新的结果集,而不会在迭代时拼接数组。

 function getKey(o) { return o.licenseId + '|' + o.reportDate + '|' + o.batchId; } var duplicateTestData = [{ licenseId: 'xxx', batchId: '123', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'yyy', batchId: '124', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'aaa', batchId: '145', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }], finalResult = [{ reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', license: {}, testType: 'P1', productType: 'Flower', batchId: '123', licenseId: 'xxx', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '124', licenseId: 'yyy', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'aaa', createType: 'DataUpload' }, { reportDate: 'Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'zzz', createType: 'DataUpload' }], hash = Object.create(null), result = []; duplicateTestData.forEach(function (a) { hash[getKey(a)] = true; }); result = finalResult.filter(function (a) { return !hash[getKey(a)]; }); console.log(result); 

ES6

 function getKey(o) { return o.licenseId + '|' + o.reportDate + '|' + o.batchId; } var duplicateTestData = [{ licenseId: 'xxx', batchId: '123', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'yyy', batchId: '124', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'aaa', batchId: '145', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }], finalResult = [{ reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', license: {}, testType: 'P1', productType: 'Flower', batchId: '123', licenseId: 'xxx', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '124', licenseId: 'yyy', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'aaa', createType: 'DataUpload' }, { reportDate: 'Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'zzz', createType: 'DataUpload' }], map = duplicateTestData.reduce((r, a) => r.set(getKey(a)), new Map), result = finalResult.filter(a => !map.has(getKey(a))); console.log(result); 

for (var a = 0; a < duplicateTestData.length; a++) {
  var dt = duplicateTestData[a];
  var dtr = new Date(dt.reportDate + '');

  for (var b = 0; b < finalResult.length; b++) {
    var fr = finalResult[b];
    var frr = new Date(fr.reportDate + '');

    //define your logic how to match two objects
    if (dtr.getTime() !== frr.getTime() &&
      dt.batchId !== fr.batchId) {
      //object matched. remove it from array

      var removed = finalResult.splice(b, 1);
      console.log('items removed', removed);
    }
  }
}

//print finalResult array
for (var c = 0; c < finalResult.length; c++) {
  console.log(finalResult[c]);
}

使用lodash:

duplicateTestData.reduce( _.reject, finalResult );

 var duplicateTestData = [ { licenseId: 'xxx', batchId: '123', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'yyy', batchId: '124', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' }, { licenseId: 'aaa', batchId: '145', reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)' } ]; var finalResult = [ { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', license: {}, testType: 'P1', productType: 'Flower', batchId: '123', licenseId: 'xxx', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '124', licenseId: 'yyy', createType: 'DataUpload' }, { reportDate: 'Fri Dec 11 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'aaa', createType: 'DataUpload' }, { reportDate: 'Fri Dec 14 2015 00:00:00 GMT+0530 (India Standard Time)', testType: 'P1', productType: 'Flower', batchId: '145', licenseId: 'zzz', createType: 'DataUpload' } ] console.log( duplicateTestData.reduce( _.reject, finalResult ) ); 
 <script src="https://cdn.jsdelivr.net/lodash/4.15.0/lodash.min.js"></script> 

其核心是_.reject() ,它与_.filter()相反:当传递一个对象时,它将使用_.matches()进行部分比较。

要为duplicateTestData中的每个条目运行它,我们可以使用.reduce() ,标准的Array函数。 我们将finalResult作为initialValue传递。 方便地,参数的顺序正确,因此我们不需要匿名函数! (我应该说lodash是一个设计得很好的库。)一旦reduce()遍历duplicateTestData中的所有条目,它将返回最终的过滤结果。

暂无
暂无

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

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