0

I have the following nested Object

const ERR_CODES = {
    INVALID_CONSUMER_ID: {
        code: 1000,
        message: 'Invalid Consumer ID',
    },
    INVALID_MOBILE: {
        code: 1001,
        message: 'Invalid Mobile Number',
    },
    INVALID_ZIPCODE: {
        code: 1002,
        message: 'Invalid Zipcode',
    },
    INVALID_FIRST_NAME: {
        code: 1000,
        message: 'First Name',
    },
}

I want to throw an error when two objects have the same code, like in the example consumer id and first name both have 1000 for error codes. What is the fastest way to go through my ERR_CODES obj and see if any code repeats?

str
  • 42,689
  • 17
  • 109
  • 127

6 Answers6

3

You can use a map to keep track of the codes and compare with it, if the code is already part of the map, you could throw an error.

const ERR_CODES = {
  INVALID_CONSUMER_ID: {
    code: 1000,
    message: 'Invalid Consumer ID',
  },
  INVALID_MOBILE: {
    code: 1001,
    message: 'Invalid Mobile Number',
  },
  INVALID_ZIPCODE: {
    code: 1002,
    message: 'Invalid Zipcode',
  },
  INVALID_FIRST_NAME: {
    code: 1000,
    message: 'First Name',
  }
};

let keys = Object.keys(ERR_CODES);
let codesMap = {};

for (let i = 0; i < keys.length; i++) {
  let key = keys[i];
  let obj = ERR_CODES[key];
  let code = obj.code;

  if (!codesMap[code]) {
    codesMap[code] = true
  } else {
    console.error('Duplicate');
  }
}
Sushanth --
  • 55,259
  • 9
  • 66
  • 105
  • I believe this is faster than @larz answer correct? – Haroun Ansari Jun 01 '18 at 19:35
  • to my knowledge, yes this would be faster. Larz answer would be something like O(nm), 2 iterations over similar length arrays and the first iteration (map) wouldnt terminate even if it had already found a code it previously saw. Sushanth answer would be 1 array iteration and would stop at the first duplicate. Both are just fine though! This one just a little more performant. – Matt Pengelly Jun 01 '18 at 19:48
2

Create an array of all of the codes present, then get all of the unique codes. If they are of equal length, there are no repeats. If the unique codes array is shorter, then there is a repeat.

const ERR_CODES = {
    INVALID_CONSUMER_ID: {
        code: 1000,
        message: 'Invalid Consumer ID',
    },
    INVALID_MOBILE: {
        code: 1001,
        message: 'Invalid Mobile Number',
    },
    INVALID_ZIPCODE: {
        code: 1002,
        message: 'Invalid Zipcode',
    },
    INVALID_FIRST_NAME: {
        code: 1000,
        message: 'First Name',
    },
};

const codes = Object.keys(ERR_CODES).map(err => ERR_CODES[err].code)

const uniq_codes = codes.reduce((p, c) => {
    if (p.indexOf(c) < 0) p.push(c);
    return p;
}, []);

console.log(codes.length == uniq_codes.length);
larz
  • 5,724
  • 2
  • 11
  • 20
  • In terms of performance, is this faster or slower than other ways? – Haroun Ansari Jun 01 '18 at 19:30
  • I suppose the only way to answer that would be to do some benchmark testing. There are probably more succinct ways, but unless you have a huge set of ERR_CODES (1000+), you don't need to worry about performance. – larz Jun 01 '18 at 19:31
1

Since you only need to check if any code is repeated, I would choose a Set to store all of your codes:

let codes_num = Object.keys(ERR_CODES).map(elem => {
    return ERR_CODES[elem].code;
});

let codes = new Set(codes_num);

Thanks to the properties of a Set, duplicated elements are just discarded. For this reason a simple check like this one:

Object.keys(ERR_CODES).length == codes.size

is going to tell you if a duplicated code has been found.

Marco Luzzara
  • 5,540
  • 3
  • 16
  • 42
0

May not be the fastest way but a way to do that

const ERR_CODES = {
    INVALID_CONSUMER_ID: {
        code: 1000,
        message: 'Invalid Consumer ID',
    },
    INVALID_MOBILE: {
        code: 1001,
        message: 'Invalid Mobile Number',
    },
    INVALID_ZIPCODE: {
        code: 1002,
        message: 'Invalid Zipcode',
    },
    INVALID_FIRST_NAME: {
        code: 1000,
        message: 'First Name',
    },
};

function isValid(data) {
    try{
    Object.keys(data).reduce((obj, key) => {
       if (data[key].code in obj) {
          throw new Error(`Duplicate code: ${data[key].code}`);
       } else {
          obj[data[key].code] = 'found';
       }
       return obj;
    }, {});
    } catch(e) {
       console.log(e.message);
       return false;
    }
    return true;
}

console.log(isValid(ERR_CODES));
Zohaib Ijaz
  • 21,926
  • 7
  • 38
  • 60
0

I will take the filter approach to check if the key exists more than one time.

With filter we can get a list of duplicate items by using 2 filters and checking the size of the the returned array. If the length is larger than 1, that means we found duplicates.

const ERR_CODES = {
  INVALID_CONSUMER_ID: {
    code: 1000,
    message: 'Invalid Consumer ID',
  },
  INVALID_MOBILE: {
    code: 1001,
    message: 'Invalid Mobile Number',
  },
  INVALID_ZIPCODE: {
    code: 1002,
    message: 'Invalid Zipcode',
  },
  INVALID_FIRST_NAME: {
    code: 1000,
    message: 'First Name',
  },
}

let codes = Object.values(ERR_CODES)

let result = codes.filter(item => codes.filter(i => i.code == item.code).length > 1)

console.log(result)

if(result.length > 0) {
  // We have duplicates throw error here
  console.error('Duplicate codes')
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
0

My take on the fastest solution would iterate over ERR_CODES only once and break once a duplicate is found:

const codes = new Set();

for (err in ERR_CODES) { 
  const {code} = ERR_CODES[err]; 
  if (codes.has(code)) { 
    console.error(`Duplicate code: ${code}`); 
    break; 
  } 
  codes.add(code); 
}
ic3b3rg
  • 14,629
  • 4
  • 30
  • 53