如何在不循环的情况下更新数组内的JS对象值?

时间:2019-06-11 14:23:23

标签: javascript node.js ecmascript-6

我知道已经有一个similar question 了,但是我的不同之处在于我只是不想找到它,我只想更新它

我有一个这样的对象的JS数组:

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,
  }
];

现在牢记这一点,我有一个名为phoneNo的属性,它保证了唯一的值。

现在,我要为给定数字切换checked的值。

我尝试过的事情:

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 :-)
    }
}

我编写了这段代码,并在一段时间内运行良好,但现在我意识到列表越来越大,并且这段代码反复迭代,这效率很低。

我想要什么?

在给定checked的值的情况下,是否可以直接切换属性phoneNo的值而无需遍历每个项目?

7 个答案:

答案 0 :(得分:3)

另一个选择是更改数据存储方式。如果phoneNo是唯一的,则可以使用电话号码作为密钥来进行数据。

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);

答案 1 :(得分:2)

  

在给定phoneNo值的情况下,是否可以直接切换所检查属性的值而无需遍历每个项目?

不是您当前的结构。但是您可以使用Map代替数组(或在数组之外),这很简单:

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

如果您需要遍历地图的值,则可以使用其values方法中的迭代器,例如:

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

如果您只有一张地图,并且由于某种原因需要获取值数组,则可以将values()与扩展符号一起使用:

const data = [...mappedData.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}`);
}

与在访问时间是线性的数组中搜索不同,对Map条目的访问时间必须是次线性的(通过使用哈希映射或类似方法实现)。

答案 2 :(得分:2)

您可以创建一个对象,其键将是电话号码,值将是将引用数组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)

答案 3 :(得分:1)

如果知道对象的索引,则只需一行即可更改它。但是,如果数组更改了对象的索引,则必须循环。

答案 4 :(得分:0)

否,您必须知道要在数组中更改的元素的索引,或者遍历所有项以找到与您要查找的项相匹配的项。

答案 5 :(得分:0)

您必须迭代数组。但是,您可以通过仅先找到匹配的索引来缩短循环时间。您可以先使用给定的phoneNo查找对象,然后切换值。尝试以下代码:

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

答案 6 :(得分:0)

非常简单而且非常快速

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);