javascript — пересечение пары ключ-значение массива объектов

Пересечение пары ключ-значение массива объектов

Прежде чем мы реализуем intersect мы сначала посмотрим, как мы ожидаем, что он будет вести себя —

 console.log ( intersect ( { a: 1, b: 2, d: 4 } , { a: 1, c: 3, d: 5 } ) // { a: 1 } , intersect ( [ 1, 2, 3, 4, 6, 7 ] , [ 1, 2, 3, 5, 6 ] ) // [ 1, 2, 3, {amp}lt;1 empty item{amp}gt;, 6 ] , intersect ( [ { a: 1 }, { a: 2 }, { a: 4, b: 5 }, ] , [ { a: 1 }, { a: 3 }, { a: 4, b: 6 }, ] ) // [ { a: 1 }, {amp}lt;1 empty item{amp}gt;, { a: 4 } ] , intersect ( { a: { b: { c: { d: [ 1, 2 ] } } } } , { a: { b: { c: { d: [ 1, 2, 3 ] } } } } ) // { a: { b: { c: { d: [ 1, 2 ] } } } } ) 

Сложные проблемы, подобные этой, облегчаются, разбивая их на более мелкие части. Для реализации intersect мы планируем merge два вызова к intersect1 , каждый из которых вносит вклад в одну сторону вычисляемого результата —

 const intersect = (left = {}, right = {}) ={amp}gt; merge ( intersect1 (left, right) , intersect1 (right, left) ) 

Реализация intersect1 остается относительно сложной из-за необходимости поддерживать как объекты, так и массивы — последовательность map , filter и reduce помогает поддерживать поток программы

 const intersect1 = (left = {}, right = {}) ={amp}gt; Object.entries (left) .map ( ([ k, v ]) ={amp}gt; // both values are objects isObject (v) {amp}amp;{amp}amp; isObject (right[k]) ? [ k, intersect (v, right[k]) ] // both values are "equal" : v === right[k] ? [ k, v ] // otherwise : [ k, {} ] ) .filter ( ([ k, v ]) ={amp}gt; isObject (v) ? Object.keys (v) .length {amp}gt; 0 : true ) .reduce ( assign , isArray (left) {amp}amp;{amp}amp; isArray (right) ? [] : {} ) 

Наконец, мы реализуем merge же, как и в других вопросах и ответах

 const merge = (left = {}, right = {}) ={amp}gt; Object.entries (right) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (left [k]) ? [ k, merge (left [k], v) ] : [ k, v ] ) .reduce (assign, left) 

Конечные зависимости —

 const isObject = x ={amp}gt; Object (x) === x const isArray = Array.isArray const assign = (o, [ k, v ]) ={amp}gt; (o [k] = v, o) 

Убедитесь, что вся программа работает в вашем браузере ниже —

 const isObject = x ={amp}gt; Object (x) === x const isArray = Array.isArray const assign = (o, [ k, v ]) ={amp}gt; (o [k] = v, o) const merge = (left = {}, right = {}) ={amp}gt; Object.entries (right) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (left [k]) ? [ k, merge (left [k], v) ] : [ k, v ] ) .reduce (assign, left) const intersect = (left = {}, right = {}) ={amp}gt; merge ( intersect1 (left, right) , intersect1 (right, left) ) const intersect1 = (left = {}, right = {}) ={amp}gt; Object.entries (left) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (right[k]) ? [ k, intersect (v, right[k]) ] : v === right[k] ? [ k, v ] : [ k, {} ] ) .filter ( ([ k, v ]) ={amp}gt; isObject (v) ? Object.keys (v) .length {amp}gt; 0 : true ) .reduce ( assign , isArray (left) {amp}amp;{amp}amp; isArray (right) ? [] : {} ) console.log ( intersect ( { a: 1, b: 2, d: 4 } , { a: 1, c: 3, d: 5 } ) // { a: 1 } , intersect ( [ 1, 2, 3, 4, 6, 7 ] , [ 1, 2, 3, 5, 6 ] ) // [ 1, 2, 3, {amp}lt;1 empty item{amp}gt;, 6 ] , intersect ( [ { a: 1 }, { a: 2 }, { a: 4, b: 5 }, ] , [ { a: 1 }, { a: 3 }, { a: 4, b: 6 }, ] ) // [ { a: 1 }, {amp}lt;1 empty item{amp}gt;, { a: 4 } ] , intersect ( { a: { b: { c: { d: [ 1, 2 ] } } } } , { a: { b: { c: { d: [ 1, 2, 3 ] } } } } ) // { a: { b: { c: { d: [ 1, 2 ] } } } } ) 

intersectAll

Выше intersect принимает только два входа и в вашем вопросе вы хотите вычислить пересечение 2 объектов. Мы реализуем intersectAll следующим образом —

 const None = Symbol () const intersectAll = (x = None, ...xs) ={amp}gt; x === None ? {} : xs .reduce (intersect, x) console.log ( intersectAll ( { a: 1, b: 2, c: { d: 3, e: 4 } } , { a: 1, b: 9, c: { d: 3, e: 4 } } , { a: 1, b: 2, c: { d: 3, e: 5 } } ) // { a: 1, c: { d: 3 } } , intersectAll ( { a: 1 } , { b: 2 } , { c: 3 } ) // {} , intersectAll () // {} ) 

Проверьте результаты в вашем браузере —

 const isObject = x ={amp}gt; Object (x) === x const isArray = Array.isArray const assign = (o, [ k, v ]) ={amp}gt; (o [k] = v, o) const merge = (left = {}, right = {}) ={amp}gt; Object.entries (right) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (left [k]) ? [ k, merge (left [k], v) ] : [ k, v ] ) .reduce (assign, left) const intersect = (left = {}, right = {}) ={amp}gt; merge ( intersect1 (left, right) , intersect1 (right, left) ) const intersect1 = (left = {}, right = {}) ={amp}gt; Object.entries (left) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (right[k]) ? [ k, intersect (v, right[k]) ] : v === right[k] ? [ k, v ] : [ k, {} ] ) .filter ( ([ k, v ]) ={amp}gt; isObject (v) ? Object.keys (v) .length {amp}gt; 0 : true ) .reduce ( assign , isArray (left) {amp}amp;{amp}amp; isArray (right) ? [] : {} ) const None = Symbol () const intersectAll = (x = None, ...xs) ={amp}gt; x === None ? {} : xs .reduce (intersect, x) console.log ( intersectAll ( { a: 1, b: 2, c: { d: 3, e: 4 } } , { a: 1, b: 9, c: { d: 3, e: 4 } } , { a: 1, b: 2, c: { d: 3, e: 5 } } ) // { a: 1, c: { d: 3 } } , intersectAll ( { a: 1 } , { b: 2 } , { c: 3 } ) // {} , intersectAll () // {} ) 

замечания

Вы хотите рассмотреть некоторые вещи, как —

 intersect ( { a: someFunc, b: x ={amp}gt; x * 2, c: /foo/, d: 1 } , { a: someFunc, b: x ={amp}gt; x * 3, c: /foo/, d: 1 } ) // { d: 1 } (actual) // { a: someFunc, c: /foo/, d: 1 } (expected) 

Мы проверяем то, что считается равным здесь в intersect1

 const intersect1 = (left = {}, right = {}) ={amp}gt; Object.entries (left) .map ( ([ k, v ]) ={amp}gt; isObject (v) {amp}amp;{amp}amp; isObject (right[k]) ? [ k, intersect (v, right[k]) ] : v === right[k] // {amp}lt;-- equality? ? [ k, v ] : [ k, {} ] ) .filter ( ... 

Если мы хотим поддерживать такие вещи, как проверка на равенство функций, RegExps или других объектов, мы можем внести необходимые изменения


рекурсивный дифференциал

В этой связанной Q {amp}amp; A мы вычисляем рекурсивный diff двух объектов

Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector