【问题标题】:Make matching of values on array faster?使数组上的值匹配更快?
【发布时间】:2023-03-25 18:28:01
【问题描述】:

这是我的代码

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  devices = ['x', 'y', 'z'];
  device;
  constructor(public navCtrl: NavController) {
    this.device = 'a';
    for(let i = 0; i<this.devices.length; i++){
      if(this.device == this.devices[i]){
        console.log('Match');
      } else {
        console.log('No matches');
      }
    }
  }
}

我在想,如果我的设备列表变得太长,那么匹配会明显变慢。所以想问问有没有更好更快更有效的方法来检查数组中是否存在值。

我想要实现的是出勤率。

我的应用会扫描 id,然后检查它是否在我的列表中。 如果匹配,我会将布尔值设置为 true(用于测试目的) 所说的布尔值将在我的列表中。 像这样的

device = {
 name: '-K8d34fsd2',
 attendance: true
};

这是我尝试过的

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  devices = [
    {
      id: 'qwerty123',
      attendance: false
    },
    {
      id: 'zxcvb123',
      attendance: false
    },
  ];
  device;
  constructor(public navCtrl: NavController) {
    this.device = 'qwerty123';
    // for(let i = 0; i<this.devices.length; i++){
    //   if(this.device == this.devices[i]){
    //     console.log('Match');
    //   } else {
    //     console.log('No matches');
    //   }
    // }

      if(this.devices.id.indexOf(this.device) > -1){
        console.log('Match');
      } else {
        console.log('No matches');
      }
  }
}

【问题讨论】:

  • 改用Set,然后mySet.has就是O(1)
  • 你的意思是这样的js吗? var numbers = [4, 9, 16, 25, 29]; var first = numbers.find(myFunction); function myFunction(value, index, array) { return value > 18; }
  • 不,我的意思是使用实际的Setnew Set(....
  • 你的数组能以任何方式排序吗?在您需要搜索之前,是否已经可以对数组执行排序?搜索性能不仅与匹配功能有关,还与不匹配时的处理有关 - 例如二进制排序等。
  • @CertainPerformance 哦,我明白了,将对此进行更多研究。谢谢楼主!

标签: javascript arrays angular performance string-matching


【解决方案1】:

您可以使用 Array.prototype.map() 在 O(n) time complexity 创建一个更新的出勤列表。

请参阅下面的实际示例。

// Input.
const devices = [{id: 'A', attendance: false}, {id: 'B', attendance: false}, {id: 'C', attendance: false}]
const deviceId = 'B'

// Update Device Attendance.
const updateDeviceAttendance = (devices, deviceId) => devices.map(x => {
  if (x.id == deviceId) return {...x, attendance: true}
  return x
})

// Ouput + Proof.
const output = updateDeviceAttendance(devices, deviceId)
console.log(output)

尽管使用对象而不是数组可以实现 O(1) 时间复杂度。

// Input.
const devices = {'A': {attendance: false}, 'B': {attendance: false}, 'C': {attendance: false}}
const deviceId = 'B'

// Update Device Attendance.
const updateDeviceAttendance = (devices, id) => ({...devices, [id]: {id, attendance: true}})

// Ouput + Proof.
const output = updateDeviceAttendance(devices, deviceId)
console.log(output)

【讨论】:

  • 谢谢先生!你帮我迈出了下一步:)
【解决方案2】:

由于您尝试根据特定 ID 查找项目,因此最快的数组不是数组,而是对象:

devices = {
   qwerty123: {attendance: true, otherData: "whatever"}, 
   zxcvb123:  {attendance: false, etcetera: "etcetera"}
}

现在您的“搜索”只是一个键查找:

devices.querty123  // returns {attendance: true, otherData: "whatever"}
devices.notarealkey // returns undefined

// when searching with a variable:
this.device = 'qwerty123';
devices[this.device] // returns the same as devices.querty123

【讨论】:

  • 当使用变量搜索时,我们不应该使用devices[value] 符号吗?
  • 是的,我也应该包括一个例子,谢谢@ConnorsFan
  • 这可能是我需要的,因为我将使用 angular fire 从 firebase 获取数据,然后将其保存到可观察的列表中
【解决方案3】:

虽然该社区的乐于助人的人输入并提交了答案,但我也试图找到一个来贡献。

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  devices = [
    {
      id: 'qwerty123',
      attendance: false
    },
    {
      id: 'zxcvb123',
      attendance: false
    },
  ];
  device;
  constructor(public navCtrl: NavController) {
    this.device = 'qwerty123';

    let result = this.devices.find( device => device.id === this.device);
    console.log(result);
  }
}

find 方法返回请求的对象,如果没有,则返回未定义的对象。 至于速度,我还没有测试过。我想其他人可能也想知道。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

【讨论】:

    【解决方案4】:

    你有一些选择。

    Array.indexOf() 这比遍历整个数组并检查每个元素是否符合条件要好得多(slighthly faster using your example on a benchmark)。

    import { Component } from '@angular/core';
    import { NavController } from 'ionic-angular';
    
    @Component({
      selector: 'page-home',
      templateUrl: 'home.html'
    })
    export class HomePage {
      devices = ['x', 'y', 'z'];
      device;
      constructor(public navCtrl: NavController) {
        this.device = 'a';
        if(this.devices.indexOf(this.device) > -1){
            console.log('Match');
        } else {
            console.log('No matches');
        }
    
      }
    }
    

    如果你可以支持 ES2016,Array.includes()indexOf() (see the same benchmark) 稍好,并且在语法上更容易阅读。

    import { Component } from '@angular/core';
    import { NavController } from 'ionic-angular';
    
    @Component({
      selector: 'page-home',
      templateUrl: 'home.html'
    })
    export class HomePage {
      devices = ['x', 'y', 'z'];
      device;
      constructor(public navCtrl: NavController) {
        this.device = 'a';
        if(this.devices.includes(this.device)){
            console.log('Match');
        } else {
            console.log('No matches');
        }
    
      }
    }
    

    编辑:由于 OP 对原始问题的编辑,我将列出使用对象进行搜索的可能方法:

    1 - for 循环:

    var test = [{name:'asdfasafdx', attendance: true}, {name:'fdsafdsay', attendance: true}, {name:'sdfasdfasz', attendance: true}];
    
    var device = {name:'fdwoierqea'};
    
    for(let i = 0; i < test.length; i++){
          if(device.name == test[i].name){
            console.log('Match');
          } else {
            console.log('No matches');
          }
    }
    

    2 - Array.filter() (faster)

    var test = [{name:'asdfasafdx', attendance: true}, {name:'fdsafdsay', attendance: true}, {name:'sdfasdfasz', attendance: true}];
    
    var device = {name:'fdwoierqea'};
    
    if(test.filter(value => value.name === device.name).length > 0){
            console.log('Match')
    
    } else {
            console.log('No matches');
    }
    

    【讨论】:

    • 它是否仍然适用于我更新的问题?感谢您的快速答复!网站也不错:)
    • 在有对象的数组上,如何使用includes和indexOf?
    • @JustineLanceT.Mojal 关于速度,使用for 循环而不是寻找事件的内置函数,该函数将永远是最快的方法。
    • 会跟着你们,非常感谢你们!编辑:没有关注按钮
    • @VictorAlencarSantos - 事实上,break 并没有改变任何东西,因为没有找到匹配项。改进来自于将console.log 语句从循环中取出,并与=== 而不是== 进行比较。通过这些更改,for 循环将等效于 indexOfincludes
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2020-07-20
    • 1970-01-01
    相关资源
    最近更新 更多