Отфильтровать два массива по одинаковому значению объекта
Есть два ID, например 1 и 2, который в обоих массивах находятся или в home_id или в away_id, но противоположный ID всегда разный. Надо найти одинаковые противоположные id, которые присутствуют в обоих массивах, остальные удалить.
Пример из жизни) есть две команды футбольные. И у них есть общие соперники. А есть те, с которыми они никогда не встречались. Команды могут играть как дома, так и в гостях.
let arr1 = [
{home_id: 1, away_id: 100},
{away_id: 1, home_id: 200},
{home_id: 300, away_id: 1},
{away_id: 1, home_id: 400},
]
let arr2 = [
{home_id: 2, away_id: 100},
{away_id: 2, home_id: 200},
{home_id: 900, away_id: 2},
{away_id: 2, home_id: 600},
]
чтобы в итоге получилось
let arr3 = [
{home_id: 2, away_id: 100},
{away_id: 2, home_id: 200},
{home_id: 1, away_id: 100},
{away_id: 1, home_id: 200}
]
Ответы (2 шт):
Возможно, есть более эффективный способ, но у меня пока вышло только так, если я правильно понял задачу.
Сначала находим для каждого массива повторяющийся идентификатор, чтобы потом, исключая его, находить противоположный идентификатор. Достаточно проверить на повтор значения из первых двух объектов каждого массива.
Затем для каждого массива создаём временный объект с ключами из противоположного идентификатора, чтобы потом можно было эффективнее искать повторения.
Наконец, включаем в результат только те значения из временных объектов, ключи которых есть в обоих временных объектакх.
const arr1 = [
{home_id: 1, away_id: 100},
{away_id: 1, home_id: 200},
{home_id: 300, away_id: 1},
{away_id: 1, home_id: 400},
];
const arr2 = [
{home_id: 2, away_id: 100},
{away_id: 2, home_id: 200},
{home_id: 900, away_id: 2},
{away_id: 2, home_id: 600},
];
const sameId1 = [...Object.values(arr1[0]), ...Object.values(arr1[1])]
.find((val, i, array) => array.lastIndexOf(val) !== i);
const sameId2 = [...Object.values(arr2[0]), ...Object.values(arr2[1])]
.find((val, i, array) => array.lastIndexOf(val) !== i);
const temp1 = arr1.reduce(
(acc, object) => {
const otherId = object.home_id !== sameId1 ? object.home_id : object.away_id;
acc[otherId] = object;
return acc;
},
{},
);
const temp2 = arr2.reduce(
(acc, object) => {
const otherId = object.home_id !== sameId2 ? object.home_id : object.away_id;
acc[otherId] = object;
return acc;
},
{},
);
const arr3 = [];
for (const [id, object] of Object.entries(temp1)) {
if (temp2[id]) arr3.push(object, temp2[id]);
}
console.log(arr3);
В результате мучительного извлечения подробностей из автора вопроса, задачу я понимаю как
"Найти объекты, в свойствах которых встречаются повторяющиеся (по всем данным) значения вне списка исключений (в примере это 1, 2)."
, и предлагаю такое решение:
let arr1 = [
{ home_id: 1, away_id: 100 },
{ away_id: 1, home_id: 200 },
{ home_id: 300, away_id: 1 },
{ away_id: 1, home_id: 400 },
];
let arr2 = [
{ home_id: 2, away_id: 100 },
{ away_id: 2, home_id: 200 },
{ home_id: 900, away_id: 2 },
{ away_id: 2, home_id: 600 },
];
function findObjectsWithNonUniqueValues(objects, ignoreValues = []) {
ignoreValues = new Set(ignoreValues);
const valuesCnt = objects.reduce((rslt, obj) => {
for (const val of Object.values(obj))
rslt[val] = (rslt[val] ?? 0) + 1;
return rslt;
}, {});
return objects.filter(obj => Object.values(obj).some(
val => !ignoreValues.has(val) && (valuesCnt[val] > 1)
));
}
console.log(findObjectsWithNonUniqueValues([...arr1, ...arr2], [1, 2]));
Для фильтрации требуется иметь статистику "повторяемости" значений каждого свойства, поэтому выполняю два прохода по данным (первый - это подсчет в хэштаблицу valuesCnt количества вхождений, а второй - собственно фильтрация массива objects).
Сделано отступление от условия "два входных массива" - вместо этого функция ожидает один массив объектов, т.к. по логике входных+выходных данных он и должен быть один (а выполнить слияние любого количества массивов не представляется проблемой - вложенные объекты при этом не копируются, всего лишь создаются ссылки на них).
Процесс мысленной компиляции и дистилляции условий задачи (возможно, это окажется полезным):
«Есть два ID, например 1 и 2 ... две команды футбольные ... два массива» ➝ значения свойств (объектов в массивах) содержат ID сущностей;
«в первом, например, 1:99, 1:66, 23:1, 33:1 и второй массив где 2:99, 66:2, 2:100, 200:2» ➝ каждый объект из входных данных представляет собой связь по ID (т.е., массив как таблица с двумя полями, и оба внешние ключи);
«И у них есть общие соперники ... Вот общих мне надо запихать в один массив ... два ID я всегда знаю, в данном случае это 1 и 2 ... но противоположный ID всегда разный» ➝ критерий фильтрации это наличие связей двух известных ID с общим неизвестным ID (x).
Две связи с x == два объекта со значением x в любом свойстве ➝ упрощаем критерий фильтра до "повторения ID где угодно" и известные ID из этого критерия исключаем (как второго участника каждой связи) ➝ учтя формат выходных данных (исходные объекты), получаем финальную формулировку задачи.