Home > Software design >  How can I determine a property that's present in all the objects of an array of arrays that con
How can I determine a property that's present in all the objects of an array of arrays that con

Time:08-01

I basically have this array of arrays:

const emptyRooms = [
    [
      {
        "kitchen": false
      },
      {
        "ballroom": false
      },
      {
        "billiard room": false
      }
    ],
    [
      {
        "ballroom": false
      },
      {
        "conservatory": false
      },
      {
        "dining room": false
      },
      {
        "library": false
      }
    ],
    [
      {
        "kitchen": false
      },
      {
        "ballroom": false
      },
      {
        "dining room": false
      },
      {
        "library": false
      }
    ],
    [
      {
        "ballroom": false
      },
      {
        "conservatory": false
      },
      {
        "billiard room": false
      },
      {
        "library": false
      }
    ]
  ]

And I wanted to determine which one of the properties is present in all of the inner arrays. I did it with a for loop but I was wondering how I could do this with map/filter/reduce. I wanted to understand array methods a little bit better, and I wanted to make it dynamic aswell so I'm struggling to solve this :(

CodePudding user response:

In these kinds of problems, I find it helpful to separate the different concerns into functions in order to make the problem easier to reason about.

In this problem specifically, collecting all the unique keys (property names) of the objects in each sub-array is something you need to do repeatedly, so it's a great candidate for a dedicated function.

Below I've created a commented code snippet which uses the Array.prototype.values() method on the top-level array to create an iterator, which is then used to compare the keys in each sub-array.

The reason that I use an iterator is because it's important to be able to create the initial set of common keys from the first sub-array, and it's also important to be able to iterate over the remaining sub-arrays. There are a number of ways to do this, but the statefulness of an iterator makes it a natural choice to me.

If you still have any questions after reading the comments in the code, then feel free to ask in a comment on this answer.

'use strict';

/** @returns Set of unique property names in an array of objects */
function collectKeys (array) {
  const keys = new Set();
  for (const obj of array) {
    for (const key in obj) keys.add(key);
  }
  return keys;
}

/** @returns Array of unique property names present in every sub-array of objects */
function findCommonKeys (array) {
  // Get an iterator for the array's values
  const iter = array.values();
  // Get the first sub-array (if it exists) from the iterator
  const {done, value} = iter.next();
  // If it doesn't exist then there are no property names to return,
  // so return an empty array
  if (done) return [];
  // Get the unique keys from the first sub-array
  const common = collectKeys(value);
  // For every remaining sub-array left in the iterator sequence...
  for (const array of iter) {
    // Skip the rest of the sub-arrays if there are no keys in the common set
    if (common.size === 0) break;
    // Get the unique keys for this sub-array of objects
    const keys = collectKeys(array);
    // For each key in the common set of keys
    for (const key of common) {
      // If the current sub-array's unique keys doesn't have it in common,
      // then delete it from the common keys
      if (!keys.has(key)) common.delete(key);
    }
  }
  // Convert the common set to an array
  return [...common];
}

const emptyRooms = [
  [
    {kitchen: false},
    {ballroom: false},
    {'billiard room': false},
  ],
  [
    {ballroom: false},
    {conservatory: false},
    {'dining room': false},
    {library: false},
  ],
  [
    {kitchen: false},
    {ballroom: false},
    {'dining room': false},
    {library: false},
  ],
  [
    {ballroom: false},
    {conservatory: false},
    {'billiard room': false},
    {library: false},
  ]
];

const commonKeys = findCommonKeys(emptyRooms);
console.log(commonKeys); // ["ballroom"]

CodePudding user response:

This is my take on the problem.

const emptyRooms = [
    [
      {
        "kitchen": false
      },
      {
        "ballroom": false
      },
      {
        "billiard room": false
      }
    ],
    [
      {
        "ballroom": false
      },
      {
        "conservatory": false
      },
      {
        "dining room": false
      },
      {
        "library": false
      }
    ],
    [
      {
        "kitchen": false
      },
      {
        "ballroom": false
      },
      {
        "dining room": false
      },
      {
        "library": false
      }
    ],
    [
      {
        "ballroom": false
      },
      {
        "conservatory": false
      },
      {
        "billiard room": false
      },
      {
        "library": false
      }
    ]
  ];

const allPropsReducer = (prev, curr)=>{

  var result = Object.getOwnPropertyNames(curr).reduce(
    (obj, key)=>{
      obj[key] = curr[key];
      return obj;
    }, prev);

  return result;

};

var allPropsObject = emptyRooms.reduce((collector, currArray)=>{
  var result = currArray.reduce(allPropsReducer, collector);
  return result;
}, {}); 

var allIncluded = emptyRooms.filter((it, idx) => {
  var room = it.reduce(allPropsReducer, {});


  var allPropertyNames = Object.getOwnPropertyNames(allPropsObject);
  var missingPropertyNames = allPropertyNames.filter((k) => {
    return !room.hasOwnProperty(k);
  })
  return missingPropertyNames.length===0;
});

console.log(allIncluded); 

  • Related