JavaScript에서 두 객체 배열의 차이를 얻는 방법
다음과 같은 두 가지 결과 집합이 있습니다.
// Result 1
[
{ value="0", display="Jamsheer" },
{ value="1", display="Muhammed" },
{ value="2", display="Ravi" },
{ value="3", display="Ajmal" },
{ value="4", display="Ryan" }
]
// Result 2
[
{ value="0", display="Jamsheer" },
{ value="1", display="Muhammed" },
{ value="2", display="Ravi" },
{ value="3", display="Ajmal" },
]
필요한 최종 결과는 이러한 배열 간의 차이입니다. 최종 결과는 다음과 같아야합니다.
[{ value="4", display="Ryan" }]
JavaScript에서 이와 같은 일을 할 수 있습니까?
네이티브 JS 만 사용하면 다음과 같이 작동합니다.
a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]
function comparer(otherArray){
return function(current){
return otherArray.filter(function(other){
return other.value == current.value && other.display == current.display
}).length == 0;
}
}
var onlyInA = a.filter(comparer(b));
var onlyInB = b.filter(comparer(a));
result = onlyInA.concat(onlyInB);
console.log(result);
Array.prototype.filter()
와 함께 사용할 수 있습니다 Array.prototype.some()
.
다음은 예입니다 (배열이 변수 result1
및에 저장되어 있다고 가정 result2
).
//Find values that are in result1 but not in result2
var uniqueResultOne = result1.filter(function(obj) {
return !result2.some(function(obj2) {
return obj.value == obj2.value;
});
});
//Find values that are in result2 but not in result1
var uniqueResultTwo = result2.filter(function(obj) {
return !result1.some(function(obj2) {
return obj.value == obj2.value;
});
});
//Combine the two arrays of unique entries
var result = uniqueResultOne.concat(uniqueResultTwo);
@Cerbrus 및 @Kasper Moerch 의 접근 방식과 아이디어가 비슷하지만 약간 더 일반적인 접근 방식을 사용합니다 . 두 개체가 같은지 확인하기 위해 조건자를 받아들이는 함수를 만들고 (여기서는 $$hashKey
속성 을 무시 하지만 아무것도 될 수 있음) 해당 조건자를 기반으로 두 목록의 대칭 차이를 계산하는 함수를 반환합니다.
a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]
var makeSymmDiffFunc = (function() {
var contains = function(pred, a, list) {
var idx = -1, len = list.length;
while (++idx < len) {if (pred(a, list[idx])) {return true;}}
return false;
};
var complement = function(pred, a, b) {
return a.filter(function(elem) {return !contains(pred, elem, b);});
};
return function(pred) {
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
};
}());
var myDiff = makeSymmDiffFunc(function(x, y) {
return x.value === y.value && x.display === y.display;
});
var result = myDiff(a, b); //=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
그것은 일찍 탈출한다는 점에서 Cerebrus의 접근법 (Kasper Moerch의 접근법과 마찬가지로)보다 한 가지 사소한 이점이 있습니다. 일치하는 항목을 찾으면 나머지 목록을 확인하지 않습니다. 나는이 있다면 curry
기능이 편리합니다, 나는 조금 다르게 이것을 할 것입니다, 그러나 이것은 잘 작동합니다.
설명
초보자를 위해 더 자세한 설명을 요청한 댓글입니다. 여기에 시도가 있습니다.
다음 함수를에 전달합니다 makeSymmDiffFunc
.
function(x, y) {
return x.value === y.value && x.display === y.display;
}
이 함수는 두 개체가 같은지 결정하는 방법입니다. 모든 기능 반환 같은 true
또는 false
, 그것은 "술어 함수를"호출 할 수 있지만, 그건 그냥 용어입니다. 요점은 makeSymmDiffFunc
두 개의 객체를 받아들이고 true
동등하다고 생각하면 반환 false
하지 않는 경우 반환하는 함수로 구성되어 있다는 것 입니다.
이를 사용하여 makeSymmDiffFunc
( "대칭 차분 함수 만들기"읽기) 새 함수를 반환합니다.
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
이것이 우리가 실제로 사용할 기능입니다. 우리는 두 개의 목록을 전달하고 두 번째가 아닌 첫 번째 요소를 찾은 다음 첫 번째가 아닌 두 번째 요소를 찾아이 두 목록을 결합합니다.
그래도 다시 살펴보면 코드에서 단서를 가져오고 다음을 사용하여 주 기능을 상당히 단순화 할 수있었습니다 some
.
var makeSymmDiffFunc = (function() {
var complement = function(pred, a, b) {
return a.filter(function(x) {
return !b.some(function(y) {return pred(x, y);});
});
};
return function(pred) {
return function(a, b) {
return complement(pred, a, b).concat(complement(pred, b, a));
};
};
}());
complement
술어를 사용하고 두 번째가 아닌 첫 번째 목록의 요소를 리턴합니다. 이것은 별도의 contains
기능을 사용하는 첫 번째 패스보다 간단 합니다.
마지막으로 기본 함수는 즉시 호출되는 함수 표현식 ( IIFE )으로 래핑되어 내부 complement
함수가 전역 범위에서 벗어나 도록합니다 .
몇 년 후 업데이트
이제 ES2015가 매우 유비쿼터스가되었으므로 동일한 기술을 더 적은 상용구로 제안합니다.
const diffBy = (pred) => (a, b) => a.filter(x => !b.some(y => pred(x, y)))
const makeSymmDiffFunc = (pred) => (a, b) => diffBy(pred)(a, b).concat(diffBy(pred)(b, a))
const myDiff = makeSymmDiffFunc((x, y) => x.value === y.value && x.display === y.display)
const result = myDiff(a, b)
//=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
ES6의 한 줄짜리 솔루션을 좋아하는 사람들을 위해 다음과 같습니다.
const arrayOne = [
{ value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer" },
{ value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed" },
{ value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi" },
{ value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal" },
{ value: "a63a6f77-c637-454e-abf2-dfb9b543af6c", display: "Ryan" },
];
const arrayTwo = [
{ value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer"},
{ value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed"},
{ value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi"},
{ value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal"},
];
const results = arrayOne.filter(({ value: id1 }) => !arrayTwo.some(({ value: id2 }) => id2 === id1));
console.log(results);
You can create an object with keys as the unique value corresponding for each object in array and then filter each array based on existence of the key in other's object. It reduces the complexity of the operation.
ES6
let a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
let b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];
let valuesA = a.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let valuesB = b.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let result = [...a.filter(({value}) => !valuesB[value]), ...b.filter(({value}) => !valuesA[value])];
console.log(result);
ES5
var a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
var b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];
var valuesA = a.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var valuesB = b.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var result = a.filter(function(c){ return !valuesB[c.value]}).concat(b.filter(function(c){ return !valuesA[c.value]}));
console.log(result);
import differenceBy from 'lodash/differenceBy'
const myDifferences = differenceBy(Result1, Result2, 'value')
This will return the difference between two arrays of objects, using the key value
to compare them. Note two things with the same value will not be returned, as the other keys are ignored.
This is a part of lodash.
I think the @Cerbrus solution is spot on. I have implemented the same solution but extracted the repeated code into it's own function (DRY).
function filterByDifference(array1, array2, compareField) {
var onlyInA = differenceInFirstArray(array1, array2, compareField);
var onlyInb = differenceInFirstArray(array2, array1, compareField);
return onlyInA.concat(onlyInb);
}
function differenceInFirstArray(array1, array2, compareField) {
return array1.filter(function (current) {
return array2.filter(function (current_b) {
return current_b[compareField] === current[compareField];
}).length == 0;
});
}
I found this solution using filter and some.
resultFilter = (firstArray, secondArray) => {
return firstArray.filter(firstArrayItem =>
!secondArray.some(
secondArrayItem => firstArrayItem._user === secondArrayItem._user
)
);
};
I've made a generalized diff that compare 2 objects of any kind and can run a modification handler gist.github.com/bortunac "diff.js" an ex of using :
old_obj={a:1,b:2,c:[1,2]}
now_obj={a:2 , c:[1,3,5],d:55}
so property a is modified, b is deleted, c modified, d is added
var handler=function(type,pointer){
console.log(type,pointer,this.old.point(pointer)," | ",this.now.point(pointer));
}
now use like
df=new diff();
df.analize(now_obj,old_obj);
df.react(handler);
the console will show
mdf ["a"] 1 | 2
mdf ["c", "1"] 2 | 3
add ["c", "2"] undefined | 5
add ["d"] undefined | 55
del ["b"] 2 | undefined
Most of answers here are rather complex, but isn't logic behind this quite simple?
- check which array is longer and provide it as first parameter (if length is equal, parameters order doesnt matter)
- Iterate over array1.
- For current iteration element of array1 check if it is present in array2
- If it is NOT present, than
- Push it to 'difference' array
const getArraysDifference = (longerArray, array2) => {
const difference = [];
longerArray.forEach(el1 => { /*1*/
el1IsPresentInArr2 = array2.some(el2 => el2.value === el1.value); /*2*/
if (!el1IsPresentInArr2) { /*3*/
difference.push(el1); /*4*/
}
});
return difference;
}
O(n^2) complexity.
If you are willing to use external libraries, You can use _.difference in underscore.js to achieve this. _.difference returns the values from array that are not present in the other arrays.
_.difference([1,2,3,4,5][1,4,10])
==>[2,3,5]
'Development Tip' 카테고리의 다른 글
자바 스크립트 상속 (0) | 2020.10.06 |
---|---|
NSOperation 및 NSOperationQueue 작업 스레드 대 기본 스레드 (0) | 2020.10.06 |
테이블의 행을 업데이트하거나 존재하지 않는 경우 INSERT하는 방법은 무엇입니까? (0) | 2020.10.06 |
ActionLink htmlAttributes (0) | 2020.10.06 |
Eclipse에서 콘솔 창을 여는 방법은 무엇입니까? (0) | 2020.10.06 |