Home > other >  How filter a set object based another set object
How filter a set object based another set object

Time:02-07

I have two Sets.

const set1 = new Set([
    {name: 'a'},
    {name: 'b', lastname: 'bb'},
    {name: 'c'},
    {name: 'd'}
]);

const set2 = new Set([
    {name: 'b'},
    {name: 'd'}
]);

Each may have several keys and values. But I need to have objects(with same keys and values) in set1 which exists in set2.

In this simple example, I need to get this: console.log(set1.filter(item => set2.has(item))) // {name: 'd'} But it returns null.

I have more than 20 keys so I can't check them one by one. How can I filter the set?

CodePudding user response:

You can do something like this:

const set1 = new Set([
    {name: 'a'},
    {name: 'b', lastname: 'bb'},
    {name: 'c'},
    {name: 'd'}
]);

const set2 = new Set([
    {name: 'b'},
    {name: 'd'}
]);

set1.forEach((value) => {
    if (![...set2].some((o) => Object.entries(o).every(([k, v], _, arr) => (Object.keys(value).length === arr.length && value[k] === v)))) {
        set1.delete(value);
    }
})

console.log([...set1]);

What this does, is to iterate through set1 and if the item at the current iteration is not the same as any item in set2 (![...set2].some(..)), it is deleted. The items are considered the same if they have the same number of keys and if the values at the same key are strictly equal.

This only works if the values of the objects in the sets are primitives, if they are not, you'll have to change value[k] === v to an appropriate comparison.

CodePudding user response:

const set1 = new Set([
    {name: 'a'},
    {name: 'b', lastname: 'bb'},
    {name: 'c'},
    {name: 'd'}
]);

const set2 = new Set([
    {name: 'b'},
    {name: 'd'}
]);

const names = [...set2].map(s2 => s2.name);

console.log([...set1].filter(item => names.includes(item.name)));

const set1 = new Set([
    {name: 'a'},
    {name: 'b', lastname: 'bb'},
    {name: 'c'},
    {name: 'd'},
    {name: 'e'}
]);

const set2 = new Set([
    {name: 'c', lastname: 'ccc'},
    {name: 'd'},
    {name: 'b', lastname: 'cc'},
    {name: 'e'}
]);

console.log([...set1].filter(item => {
    const s2Arr = [...set2];
    const itemKeys = Object.keys(item);
    for(let i = 0; i < s2Arr.length; i  ){
        const s2Obj = s2Arr[i];
        const s2ObjKeys = Object.keys(s2Obj);
        if(s2ObjKeys.length == itemKeys.length){
            let oneSame = true;
            for(let j = 0; j < s2ObjKeys.length; j  ){
                const s2ObjKey = s2ObjKeys[j];
                if(item[s2ObjKey] != s2Obj[s2ObjKey]){
                    oneSame = false;
                }
            }
            if(oneSame)
              return true;
        }
    }
    return false;
}));

CodePudding user response:

If I understand your requirement correctly, you want to find out all the matching objects in set2 from Set1 without comparing via object key as keys can be dynamic.

You can try this :

const set1 = new Set([
    {name: 'a'},
    {name: 'b', lastname: 'bb'},
    {name: 'c'},
    {name: 'd'}
]);

const set2 = new Set([
    {name: 'b'},
    {name: 'd'}
]);

// Converting set into an array
const set1Array = Array.from((set1));
const set2Array = Array.from((set2));

const result = set1Array.filter((item) => JSON.stringify(set2Array).includes(JSON.stringify(item)));

console.log(result)

CodePudding user response:

One could write a generic solution which compares pure, thus JSON conform, data structures regardless of any object's nesting depth/level and (creation time) key order.

Such a function would be self recursive for Array item (order matters) and Object property (key order does not matter) comparison. Otherwise values are compared strictly.

function isDeepDataStructureEquality(a, b) {
  let isEqual = (a === b);

  if (!isEqual) {
    if (Array.isArray(a) && Array.isArray(b)) {

      isEqual = (a.length === b.length) && a.every(
        (item, idx) => isDeepDataStructureEquality(item, b[idx])
      );
    } else if (
      a && b
      && (typeof a === 'object')
      && (typeof b === 'object')
    ) {
      const aKeys = Object.keys(a);
      const bKeys = Object.keys(b);

      isEqual = (aKeys.length === bKeys.length) && aKeys.every(
        (key, idx) => isDeepDataStructureEquality(a[key], b[key])
      );
    }
  }
  return isEqual;
}

const objA = {
  name: 'foo',
  value: 1,
  obj: {
    z: 'z',
    y: 'y',
    a: {
      name: 'bar',
      value: 2,
      obj: {
        x: 'x',
        w: 'w',
        b: 'b',
      },
      arr: ['3', 4, 'W', 'X', {
        name: 'baz',
        value: 3,
        obj: {
          k: 'k',
          i: 'i',
          c: 'c',
        },
        arr: ['5', 6, 'B', 'A'],
      }],
    },
  },
  arr: ['Z', 'Y', 1, '2'],
};

const objB = {
  arr: ['Z', 'Y', 1, '2'],
  obj: {
    z: 'z',
    y: 'y',
    a: {
      obj: {
        x: 'x',
        w: 'w',
        b: 'b',
      },
      arr: ['3', 4, 'W', 'X', {
        obj: {
          k: 'k',
          i: 'i',
          c: 'c',
        },
        name: 'baz',
        value: 3,
        arr: ['5', 6, 'B', 'A'],
      }],
      name: 'bar',
      value: 2,
    },
  },
  name: 'foo',
  value: 1,
};

const objC = {
  arr: ['Z', 'Y', 1, '2'],
  obj: {
    z: 'z',
    y: 'y',
    a: {
      obj: {
        x: 'x',
        w: 'w',
        b: 'b',
      },
      arr: ['3', 4, 'W', 'X', {
        obj: {
          k: 'k',
          i: 'i',
          c: 'c',
        },
        name: 'baz',
        value: 3,
        arr: ['5', 6, 'B', 'A'],
      }],
      name: 'bar',
      value: 2,
    },
  },
  name: 'foo',
  value: 2,
};

console.log(
  'isDeepDataStructureEquality(objA, objB) ?..',
  isDeepDataStructureEquality(objA, objB)
);
console.log(
  'isDeepDataStructureEquality(objA, objC) ?..',
  isDeepDataStructureEquality(objA, objC)
);
console.log(
  'isDeepDataStructureEquality(objB, objC) ?..',
  isDeepDataStructureEquality(objB, objC)
);
console.log(
  'isDeepDataStructureEquality(objB, objA) ?..',
  isDeepDataStructureEquality(objB, objA)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Based on the above implementation of isDeepDataStructureEquality one can solve the OP's task, that actually looks for the intersection of two list structures, by additionally providing a getIntersectionOfDeeplyEqualDataStructures functionality ...

function getIntersectionOfDeeplyEqualDataStructures(a, b) {
  return [...a].reduce((collector, sourceItem) => {

    const { target, intersection } = collector;

    const targetIndex = target.findIndex(targetItem =>
      isDeepDataStructureEquality(targetItem, sourceItem)
    );
    if (targetIndex >= 0) {
      // collect the intersection
      // of both source and target.

      intersection.push(target[targetIndex]);
    }
    return collector;

  }, { target: [...b], intersection: [] }).intersection;
}

const set1 = new Set([
  { name: 'a' },
  { name: 'b', lastname: 'bb' },
  { name: 'c' },
  { name: 'd' }
]);
const set2 = new Set([
  { name: 'b' },
  { name: 'd' },
]);
console.log(
  "getIntersectionOfDeeplyEqualDataStructures(set1, set2) ...",
  getIntersectionOfDeeplyEqualDataStructures(set1, set2)
);

const set3 = new Set([
  { name: 'a' },
  { name: 'b', lastname: 'bb' },
  { name: 'c' },
  {
    name: 'd',
    list: ['foo', 1, null, false, 0, {
      foo: { bar: { baz: 'bizz', buzz: '' } }
    }],
  },
]);
const set4 = new Set([
  {
    list: ['foo', 1, null, false, 0, {
      foo: { bar: { buzz: '', baz: 'bizz' } }
    }],
    name: 'd',
  },
  { name: 'b' },
]);
console.log(
  "getIntersectionOfDeeplyEqualDataStructures(set3, set4) ...",
  getIntersectionOfDeeplyEqualDataStructures(set3, set4)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  function isDeepDataStructureEquality(a, b) {
    let isEqual = (a === b);

    if (!isEqual) {
      if (Array.isArray(a) && Array.isArray(b)) {

        isEqual = (a.length === b.length) && a.every(
          (item, idx) => isDeepDataStructureEquality(item, b[idx])
        );
      } else if (
        a && b
        && (typeof a === 'object')
        && (typeof b === 'object')
      ) {
        const aKeys = Object.keys(a);
        const bKeys = Object.keys(b);

        isEqual = (aKeys.length === bKeys.length) && aKeys.every(
          (key, idx) => isDeepDataStructureEquality(a[key], b[key])
        );
      }
    }
    return isEqual;
  }
</script>

  •  Tags:  
  • Related