Determining incomplete sections in Javascript object

44 views Asked by At

I have a JavaScript object with several properties:

{
  banking: {
    account_number: null,
    account_type: null,
    bank_name: null,
    debit_day: null
  },
  fitment: {
    date: null,
    terms: null
  },
  personal_info: {
    email: null,
    IDNumber: null,
    mobile: null,
    name: null,
    residential_address: null,
    surname: null,
    title: null,
    work_address: null,
    work_tel: null
  },
  vehicle: {
    brand: null,
    colour: null,
    model: null,
    registration: null,
    vin: null,
    year: null
  }
}

All top level properties and nested properties has default value of null.

I'm trying to figure out a way to categorize the properties into three groups, namely:

empty, partial and complete.

"empty" being a case that all values within a section are set as null.

"partial" being that some values within a section have been set (not all null)

"complete" being that no values within a section are set to null. All have values.

My first attempt was with utilizing the Underscore library with _.some(), however I can't seem to wrap my head around catering for all group scenarios.

Some help and guidance will be much appreciated.

Thanks!

2

There are 2 answers

1
Mr. Polywhirl On BEST ANSWER

You could check for every first, and then follow-up with some, or default to empty.

const main = () => {
  const sectionStatus = Object.fromEntries(
    Object.entries(sections).map(([section, data]) => [
      section,
      Object.entries(data).every(([id, value]) => value !== null)
        ? 'complete'
        : Object.entries(data).some(([id, value]) => value !== null)
          ? 'partial'
          : 'empty'
    ]));
  
  console.log(sectionStatus);
};

const sections = {
  banking: {
    account_number: '555',
    account_type: null,
    bank_name: null,
    debit_day: null
  },
  fitment: {
    date: new Date(),
    terms: 'foobar'
  },
  personal_info: {
    email: null,
    IDNumber: null,
    mobile: null,
    name: null,
    residential_address: null,
    surname: null,
    title: null,
    work_address: null,
    work_tel: null
  },
  vehicle: {
    brand: null,
    colour: null,
    model: null,
    registration: null,
    vin: null,
    year: null
  }
};

main();
.as-console-wrapper { top: 0; max-height: 100% !important; }

Output

{
  "banking": "partial",
  "fitment": "complete",
  "personal_info": "empty",
  "vehicle": "empty"
}

If you want to optimize this you can mark each field with a 1 (not null) or 0 (null) and reduce the values.

const main = () => {
  const sectionStatus = Object.fromEntries(
    Object.entries(sections).map(([section, data]) => { 
      const flags = Object.values(data).map((v) => v !== null ? 1 : 0);
      const state = flags.reduce((a, b) => a & b, 1) === 1 // or (a * b)
        ? 'complete'
        : flags.reduce((a, b) => a | b, 0) === 1 // or (a + b) > 0
          ? 'partial'
          : 'empty';
      return [section, state];
    }, []));
  
  console.log(sectionStatus);
};

const sections = {
  banking: {
    account_number: '555',
    account_type: null,
    bank_name: null,
    debit_day: null
  },
  fitment: {
    date: new Date(),
    terms: 'foobar'
  },
  personal_info: {
    email: null,
    IDNumber: null,
    mobile: null,
    name: null,
    residential_address: null,
    surname: null,
    title: null,
    work_address: null,
    work_tel: null
  },
  vehicle: {
    brand: null,
    colour: null,
    model: null,
    registration: null,
    vin: null,
    year: null
  }
};

main();
.as-console-wrapper { top: 0; max-height: 100% !important; }

0
Julian On

You can further decompose this problem by also using _.groupBy. First, a function just to determine the category of a single section:

function category(section) {
    return _.every(section, _.isNull) ? 'empty' :
           _.some(section, _.isNull) ? 'partial' : 'complete';
}

Then, combine this with _.groupBy to create an array of original objects for each category:

_.groupBy(sections, category)

Putting it all together:

var sections = {
  banking: {
    account_number: null,
    account_type: null,
    bank_name: null,
    debit_day: null
  },
  fitment: {
    date: null,
    terms: null
  },
  personal_info: {
    email: null,
    IDNumber: null,
    mobile: null,
    name: 'Jane Doe',
    residential_address: null,
    surname: null,
    title: null,
    work_address: null,
    work_tel: null
  },
  vehicle: {
    brand: null,
    colour: null,
    model: null,
    registration: null,
    vin: null,
    year: null
  }
};

function category(section) {
    return _.every(section, _.isNull) ? 'empty' :
           _.some(section, _.isNull) ? 'partial' : 'complete';
}

console.log(_.groupBy(sections, category));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script>