Вот версия, которая использует этот Set
объект для ускорения поиска. Вот основная логика:
- Он помещает каждый массив в качестве аргумента в отдельный объект Set (чтобы облегчить быстрый поиск).
- Затем он выполняет итерацию каждого переданного массива и сравнивает его с другими объектами Set (те, которые не сделаны из массива, который повторяется).
- Если элемент не найден ни в одном из других наборов, он добавляется к результату.
Итак, он начинается с первого массива [1, 1, 2, 6]
. Так 1
как не найдено ни в одном из других массивов, каждое из первых двух 1
значений добавляется к результату. Затем он 2
находится во втором наборе, поэтому он не добавляется к результату. Тогда 6
он не найден ни в одном из двух других наборов, поэтому он добавляется к результату. Тот же процесс повторяется для второго массива, .indexOf()
где 2
и 3
находятся в других наборах, но 5
не так 5
добавляется к результату. И для последнего массива только 4
в других наборах не найдено. Итак, конечный результат function symDiff() { var sets = [], result = []; // make copy of arguments into an array var args = Array.prototype.slice.call(arguments, 0); // put each array into a set for easy lookup args.forEach(function(arr) { sets.push(new Set(arr)); }); // now see which elements in each array are unique // e.g. not contained in the other sets args.forEach(function(array, arrayIndex) { // iterate each item in the array array.forEach(function(item) { var found = false; // iterate each set (use a plain for loop so it's easier to break) for (var setIndex = 0; setIndex < sets.length; setIndex++) { // skip the set from our own array if (setIndex !== arrayIndex) { if (sets[setIndex].has(item)) { // if the set has this item found = true; break; } } } if (!found) { result.push(item); } }); }); return result; } var r = symDiff([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]); log(r); function log(x) { var d = document.createElement("div"); d.textContent = JSON.stringify(x); document.body.appendChild(d); }
.
Эти Set
объекты используются для удобства и производительности. Можно было бы использовать их Set
для поиска в каждом массиве, или вы могли бы сделать свой собственный поиск по типу с простым объектом, если бы не хотели полагаться на объект Set. Также есть частичный полипол для объекта Set, который будет работать здесь в этом ответе .
function symDiff() {
var sets = [], result = [], LocalSet;
if (typeof Set === "function") {
try {
// test to see if constructor supports iterable arg
var temp = new Set([1,2,3]);
if (temp.size === 3) {
LocalSet = Set;
}
} catch(e) {}
}
if (!LocalSet) {
// use teeny polyfill for Set
LocalSet = function(arr) {
this.has = function(item) {
return arr.indexOf(item) !== -1;
}
}
}
// make copy of arguments into an array
var args = Array.prototype.slice.call(arguments, 0);
// put each array into a set for easy lookup
args.forEach(function(arr) {
sets.push(new LocalSet(arr));
});
// now see which elements in each array are unique
// e.g. not contained in the other sets
args.forEach(function(array, arrayIndex) {
// iterate each item in the array
array.forEach(function(item) {
var found = false;
// iterate each set (use a plain for loop so it's easier to break)
for (var setIndex = 0; setIndex < sets.length; setIndex++) {
// skip the set from our own array
if (setIndex !== arrayIndex) {
if (sets[setIndex].has(item)) {
// if the set has this item
found = true;
break;
}
}
}
if (!found) {
result.push(item);
}
});
});
return result;
}
var r = symDiff([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]);
log(r);
function log(x) {
var d = document.createElement("div");
d.textContent = JSON.stringify(x);
document.body.appendChild(d);
}
Одной из ключевых частей этого кода является то, как он сравнивает данный элемент с наборами из других массивов. Он просто выполняет итерацию по списку объектов Set, но пропускает объект Set, который имеет тот же индекс в массиве, что и повторяющийся массив. Это пропускает Set из этого массива, поэтому он ищет только элементы, которые существуют в других массивах. Это позволяет сохранить дубликаты, которые встречаются только в одном массиве.
Вот версия, которая использует Set
объект, если он присутствует, но добавляет замену для подростков, если нет (так это будет работать в более старых браузерах):
function sym() {
var arrays = [].slice.apply(arguments);
return [].concat.apply([], // concatenate
arrays.map( // versions of the arrays
function(array, i) { // where each array
return array.filter( // is filtered to contain
function(elt) { // those elements which
return !arrays.some( // no array
function(a, j) { //
return i !== j // other than the current one
&& a.indexOf(elt) >= 0 // contains
;
}
);
}
);
}
)
);
}