Justine M.
Justine M.

Reputation: 379

Make matching of values on array faster?

This is my code

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

I'm thinking if my devices list becomes too long then the matching will become significantly slower. So I would like to ask if there is a better, faster and more efficient way of checking if value exists in array.

What I'm trying to implement is attendance.

My app will scan for ids then check if it is in my list. If there is a match, I will set a boolean to true(for testing purposes) The said boolean will be on my list. Something like this

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

Here's what I tried

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

Upvotes: 3

Views: 847

Answers (4)

Arman Charan
Arman Charan

Reputation: 5797

You can create an updated list of attendance in O(n) time complexity using Array.prototype.map().

See below for a practical example.

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

Although, O(1) time complexity can be achieved using objects, rather than arrays.

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

Upvotes: 1

Daniel Beck
Daniel Beck

Reputation: 21485

Since you're trying to look up items based on a specific ID, the fastest array is not an array, it's an object:

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

Now your "search" is simply a key lookup:

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

Upvotes: 2

Justine M.
Justine M.

Reputation: 379

While the helpful people of this community typed and submitted an answer, I tried to find one too to contribute.

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

the find method returns the asked object and if there are none, gives back undefined. As for speed, I have not tested it yet. I thought others might want to know too. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

Upvotes: 0

undefined is our god
undefined is our god

Reputation: 511

You have some options there.

Array.indexOf() which is way better (slighthly faster using your example on a benchmark) than iterating over the whole array and checking if every element matches the condition.

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

  }
}

And if you can support ES2016, Array.includes() is slightly better than indexOf() (see the same benchmark) and syntatically easier to read.

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

  }
}

EDIT: Due to OP's edit on the original question, i'll list the possible ways of doing the search with objects:

1 - for loop:

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

Upvotes: 2

Related Questions