How to update JS object value inside an array without looping?

Viewed 3122

I know that there is a similar question already answered, but mine is different in a way that I just don't want to find it, I just want to update it

I have a JS array of objects like this:

let data = [
  {
    contact_id: 15,
    use_id: 16,
    name: 'ABC',
    phoneNo: '0092123456789',
    checked: false,
  },
  {
    contact_id: 16,
    use_id: 22,
    name: 'DEF',
    phoneNo: '0092123456788',
    checked: false,
  },
  {
    contact_id: 17,
    use_id: 24,
    name: 'XYZ',
    phoneNo: '0092123456787',
    checked: false,
  }
];

Now with this in mind, I have a property named phoneNo which guaranteed unique values.

Now what I want is to toggle the value of checked for a given number.

What I have tried:

for (let i = 0; i < data.length; i++) {
    if (data[i]['phoneNo'] === item.phoneNo) {
        data[i]['checked'] = !data[i]['checked'];
        break; // to make it a little efficent :-)
    }
}

I wrote this code and it worked fine for a while but now I have realized that the list is growing larger and larger and this code iterates over and over again, which is very inefficient.

What I want?

Is there a way that I could directly toggle the value of the property checked given the value of phoneNo without looping over every single item?

7 Answers

Another option is to change the way your data is stored. If phoneNo is unique you could make data with phone numbers being the keys.

let data2={
  '0092123456789':{
    contact_id: 15,
    use_id: 16,
    name: 'ABC',
    checked: false,
  },
  '0092123456788':{
    contact_id: 16,
    use_id: 22,
    name: 'DEF',
    checked: false,
  },
  '0092123456787':{
    contact_id: 17,
    use_id: 24,
    name: 'XYZ',
    checked: false,
  }};
myPhoneNo = '0092123456787';
data2[myPhoneNo].checked = true;
console.log(data2);

Is there a way that I could directly toggle the value of the property checked given the value of phoneNo without looping over every single item?

Not with your current structure. But you can use a Map instead of (or in addition to) the array, and then it's trivial:

const entry = mappedData.get(item.phoneNo);
entry.checked = !entry.checked;

If you need to loop through the map's values, you can use the iterator from its values method, for instance:

for (const entry of mappedData) {
    // ...
}

If you have just a map and need to get an array of values for some reason, you can use values() with spread notation:

const data = [...mappedData.values()];

Here's an example using just a map, without the array, and looping through the map's values:

// ONE TIME, add and remove entries as needed
let mappedData = new Map([
  {
    contact_id: 15,
    use_id: 16,
    name: 'ABC',
    phoneNo: '0092123456789',
    checked: false,
  },
  {
    contact_id: 16,
    use_id: 22,
    name: 'DEF',
    phoneNo: '0092123456788',
    checked: false,
  },
  {
    contact_id: 17,
    use_id: 24,
    name: 'XYZ',
    phoneNo: '0092123456787',
    checked: false,
  }
].map(entry => [entry.phoneNo, entry]));

console.log("Before:");
for (const {phoneNo, checked} of mappedData.values()) {
    console.log(`${phoneNo}: ${checked}`);
}

// Each time you want to toggle
let phoneNo = '0092123456788';
console.log(`Checking ${phoneNo}...`);
let entry = mappedData.get(phoneNo);
entry.checked = !entry.checked;

console.log("After:");
for (const {phoneNo, checked} of mappedData.values()) {
    console.log(`${phoneNo}: ${checked}`);
}

Unlike searching an array, where the access time is linear, access time to a Map's entries is required to be sublinear (achieved by using hash maps or similar).

You can create an object whose keys will be the phone numbers and values will be object that will refer the object in the array data

const obj = {}

let data = [ { contact_id: 15, use_id: 16, name: 'ABC', phoneNo: '0092123456789', checked: false, }, { contact_id: 16, use_id: 22, name: 'DEF', phoneNo: '0092123456788', checked: false, }, { contact_id: 17, use_id: 24, name: 'XYZ', phoneNo: '0092123456787', checked: false, } ];

data.forEach(x => {
  obj[x.phoneNo] = x;
})

let given = '0092123456788';
obj[given].checked = !obj[given].checked

console.log(data)

If you know the index of the object then you can just change it in 1 line. How ever, if the array changes the index of the object then you have to loop.

No, you must know the index of the element you want to change in the array or loop through all items to find the one that matches what you're looking for.

You have to iterate the array. But you can shorten your loop by only finding the matching index first. You can find the object with the given phoneNo first and then toggle the value. Try the following code:

''' const matchData = data.find(x => x.phoneNo === item.phoneNo) matchData.checked = !matchData.checked '''

Very simple and Very fast

var data = [{
    contact_id: 15,
    use_id: 16,
    name: 'ABC',
    phoneNo: '0092123456789',
    checked: false,
  },
  {
    contact_id: 16,
    use_id: 22,
    name: 'DEF',
    phoneNo: '0092123456788',
    checked: false,
  },
  {
    contact_id: 17,
    use_id: 24,
    name: 'XYZ',
    phoneNo: '0092123456787',
    checked: false,
  }],
    result = data.some(function(x){return '0092123456787'==x.phoneNo ? true:false});
    console.log(result);
Related