#javascript #arrays #object #intersection
#javascript #массивы #объект #пересечение
Вопрос:
Я пытаюсь найти разницу между двумя объектами на основе их ключей, результатом должен быть повторно хэшированный объект интереса двух объектов с сохраненными ключами, например:
a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};
b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true};
Вывод должен быть:
[3] = {'data': true};
[4] = {'data': true};
[5] = {'data': true};
Пока у меня есть это:
var intersection = a.filter(x => b.includes(x))
Я создал скрипку ниже, но результатом является пустой массив:
Комментарии:
1. Пожалуйста, не ссылайтесь на внешний код. Ваш пример достаточно мал, чтобы включить его в качестве фрагмента стека. Также неясно, что вы пытаетесь протестировать. Вы проверяете пересечение по индексу? если да…
var intersection = a.filter((x, i) => b[i].data === x.data)
2. Да, пересечение по индексу, но я хочу сохранить индекс. Приведенный пример, как и мой собственный, находит пересечение, но не сохраняет исходные ключи
3. @mrhr да, извините, что это неправильно, вывод должен быть просто объектом, в котором совпадают пересекающиеся ключи, значения не важны, важны только ключи
4. Ваш результат — это пересечение, а не объединение. Пожалуйста, отредактируйте заголовок или вопрос.
Ответ №1:
Я просто немного изменил ваш код, и я думаю, что это то, что вы ищете:
var incoming = [];
var cookie = [];
incoming[3] = {'data': true};
incoming[4] = {'data': true};
incoming[5] = {'data': true};
cookie[2] = {'data': true};
cookie[3] = {'data': true};
cookie[4] = {'data': true};
cookie[5] = {'data': true};
console.log(typeof(cookie));
var x = Object.keys(incoming);
var y = Object.keys(cookie);
var intersection = x.filter(z => y.includes(z))
var result = {}
for (let i of intersection) {
result[i] = incoming[i]
}
//var intersection = incoming.filter(x => cookie.some(y => x === y))
//var intersection = Object.keys(cookie).filter({}.hasOwnProperty.bind(incoming));
//var intersection = (pred) => (incoming,cookie) => incoming.filter(x => !cookie.some(y => pred(x, y)))
console.log(incoming);
console.log(cookie);
console.log(intersection);
console.log(result);
Посмотрите на журнал консоли result
.
Просто немного больше информации о том, что здесь происходит: если вы хотите иметь ключи и значения, вы должны использовать объект вместо массива. То, как вы используете массивы, вы также создаете индексы [0], [1] и [2] со значениями undefined
, и именно так работает javascript, когда вы используете индекс для массива, и в упомянутом массиве отсутствуют предыдущие индексы.
Ответ №2:
Для сравнения значений это может быть так же просто, как один map()
вызов, хотя вам нужно будет учитывать разные длины двух массивов и настраивать возвращаемое значение для несопоставимых значений.
const intersection = a.map((x, i) => b[i].data === x.data ? {...x} : undefined);
const a = [],
b = [];
a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};
b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true};
const intersection = a.map((x, i) => b[i].data === x.data ? {...x} : undefined);
console.log(intersection)
Для сравнения ключей вам необходимо получить доступ к Object.keys()
и сравнить по мере необходимости. Здесь я использую some()
вызов, чтобы проверить, не совпадают ли какие-либо ключи.
Вы заметите, что если вы добавите несовпадающий ключ ( b[5] = {'data': true, 'id': 1};
), это приведет к пересечению по сравнению a
с b
, но не в другом направлении. (Все ключи in a
находятся внутри b
, но не все ключи b
находятся внутри a
);
const a = [],
b = [];
a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};
b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true, 'id': 1};
function intersectByAllKeys(arr1, arr2) {
return arr1.map((x, i) => {
const arr2Keys = arr2[i] ? Object.keys(arr2[i]) : [];
return Object.keys(x).some(k => arr2Keys.indexOf(k) < 0) ? undefined : {...x};
});
}
console.log(intersectByAllKeys(a, b))
console.log(intersectByAllKeys(b, a))
Чтобы вернуть истинное пересечение, вам нужно будет сравнить оба направления. Поскольку map()
и forEach()
пропускать неопределенные записи, проще всего использовать for()
цикл здесь. Кроме того, поскольку пересечение никогда не будет длиннее, чем короче из предоставленного массива, мы будем выполнять итерации на основе длины более короткого массива (здесь достигается путем деструктурирования аргументов после сортировки const [a, b] = [...arguments].sort((a, b) => (a.length - b.length))
).
const a = [],
b = [];
a[3] = {'data': true};
a[4] = {'data': true, 'id': 3};
a[5] = {'data': true};
b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true, 'id': 0};
b[5] = {'data': true, 'id': 1};
function missingKeys(a, b) {
return a.some(k => b.indexOf(k) < 0);
}
function intersectSymetricallyByAllKeys(arr1, arr2) {
const [a, b] = [...arguments].sort((a, b) => (a.length - b.length));
const intersection = [];
for (let i=0; i<a.length; i ){
if (!a[i] || !b[i]) {
intersection[i] = undefined;
} else {
const aKeys = Object.keys(a[i]) ?? [];
const bKeys = Object.keys(b[i]) ?? [];
intersection[i] = missingKeys(aKeys,bKeys) || missingKeys(bKeys,aKeys) ?
undefined : {...a[i]}
}
}
return intersection;
}
console.log(intersectSymetricallyByAllKeys(a, b));
console.log(intersectSymetricallyByAllKeys(b, a));