Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript (ES6): any more efficient way than "for loops"?

this is not a duplicate. please see my comment below!

does somebody knows an more efficient solution than for loops in ES6?

I have written the following, which lacks of performance. Any improvement ideas? Highly appreciated.

Basically i have an object regarding cars and an array about user preferences. Expected behavior is to push all relevant car names into an array.

Users can give any amount of preferences. A car name should be only pushed, if ALL specifications are mentioned in preferences. Therefore some preferences will be "leftovers".

For that reason in the following example Honda appears, but not BMW, which is the expected (but very slow behavior).

// Car objects
const cars = [{
    name: "Honda",
    category: "eco",
    specs: {
      0: "green",
      1: "fast",
      2: "automatic"
    }
  },
  {
    name: "BMW",
    category: "sport",
    specs: {
      0: "blue",
      1: "fast",
      2: "automatic"
    }
  }
]

// User preferences
const preferences = ["green", "fast", "4x4", "automatic", "panorama"]

// function to get length/amount of car specifications
function objsize(Myobj) {
  var osize = 0,
    key;
  for (key in Myobj) {
    if (Myobj.hasOwnProperty(key)) osize++;
  }
  return Object(osize);
};


//function to check if ALL specifications are included in the user preferences
function checkSpecs(spec_item) {
  return preferences.includes(spec_item)
}

// main function
function filter_func() {

  //final results
  let matched_cars = []


  for (i = 0; i < objsize(cars); i++) {

    let specs_collector = []

    for (j = 0; j < objsize(cars[i].specs); j++) {
      specs_collector.push(cars[i].specs[j])
    }

    if (specs_collector.every(checkSpecs) === true) {
      matched_cars.push(cars[i].name)
      specs_collector = []
    }

  }
  console.log(matched_cars)
}

filter_func()
like image 978
Umut885 Avatar asked Dec 10 '22 04:12

Umut885


2 Answers

You can't really avoid looking at every car and you can't avoid looking at every spec in the car because you want to test each of those. You can avoid looping over the preferences every time by using a Set.

So this may or may not be faster, but it's much simpler and much easier to understand because the code almost reads like English: filter cars where every spec is in the preferences:

// Car objects
const cars = [{
    name: "Honda",
    category: "eco",
    specs: ["green", "fast","automatic"]
    },
  {
    name: "BMW",
    category: "sport",
    specs: ["blue", "fast","automatic"]
    }
]

const preferences = new Set(["green", "fast", "4x4", "automatic", "panorama"])

let filtered = cars.filter(car => car.specs.every(spec => preferences.has(spec)))
console.log(filtered)
like image 111
Mark Avatar answered Dec 28 '22 07:12

Mark


-- EDIT --

Using the data in the OP:

const array_intersect = (a, b) => a.filter( i => (b.indexOf(i) >= 0) )
const a_contains_b = (a, b) => array_intersect(a, b).length == b.length

var cars = [{
    name: "Honda",
    category: "eco",
    specs: ["green", "fast", "automatic"]
  },
  {
    name: "BMW",
    category: "sport",
    specs: ["blue", "fast", "automatic"]
  }
]

const preferences = ["green", "fast", "4x4", "automatic", "panorama"]

let filtered = cars.filter(car => a_contains_b(preferences, car.specs))
console.log(filtered);
like image 27
Yoshimitsu Avatar answered Dec 28 '22 08:12

Yoshimitsu