this is not a duplicate. please see my ment 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()
this is not a duplicate. please see my ment 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()
Share
Improve this question
edited Oct 16, 2018 at 23:49
Umut885
asked Oct 16, 2018 at 23:27
Umut885Umut885
1751 silver badge16 bronze badges
13
- 2 Possible duplicate of Check if every element in one array is in a second array – Heretic Monkey Commented Oct 16, 2018 at 23:29
- @HereticMonkey please remove "possible duplicate label". The initial title name was for another question on stackoverflow. I am looking for an more efficient way than for loops. The suggested solution uses for loops. – Umut885 Commented Oct 16, 2018 at 23:41
- 2 "I have written the following, which lacks of performance." What's the performance? How did you measure it? Whenever you have a collection values that needs to be processed, you have to use some kind of loop to process each value, whether it is explicit or implicit. – Felix Kling Commented Oct 16, 2018 at 23:49
-
1
FWIW,
objsize
is unnecessary and wrong.Object(osize)
creates an a Number object, which means that5 === Object(5)
isfalse
. To iterate over an array, usefor(var i = 0; i < array.length; i++)
orfor (var item of arr)
orarr.forEach(function(item) {})
). To iterate over an object, usefor (var prop in obj)
. But it looks likecars[i].specs
should really be an array, not an object. – Felix Kling Commented Oct 16, 2018 at 23:54 -
2
"The desired solution is without any "for loops" which are slow by design." They are not slow "by design". What makes you think that?
for
loops are heavily optimized in browsers. Of course a loop might not be the "best" solution for a problem, but that's a different issue. – Felix Kling Commented Oct 16, 2018 at 23:56
3 Answers
Reset to default 9You 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)
-- 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);
There is no way to escape at least one loop. You always have to loop through all the cars, be it with a for... or with another construct like array.filter(). But there is another way to gain performance. You can use bitmasks. This would require changing the data structure of the car object so that each car already contains the bitmask corresponding to its specs, and when the user chooses the desired specs, likewise the spec codes should be added. (However, I suspect this might be too much hassle for little gain.)
// Let's pretend there are preset binary digits corresponding
// to each one of the available preferences:
//
// "blue" => 1
// "green" => 2
// "red" => 4
// "fast" => 8
// "slow" => 16
// "automatic" => 32
// "4x4" => 64
// "panorama" => 128
//
// You would encode this into the data before processing
var cars = [{
name: "Honda",
category: "eco",
specs: ["green", "fast", "automatic"],
bin_specs: 42 // 2 + 8 + 32
},
{
name: "BMW",
category: "sport",
specs: ["blue", "fast", "automatic"],
bin_specs: 41 // 1 + 8 + 32
}
]
const preferences = ["green", "fast", "4x4", "automatic", "panorama"]
const bin_preferences = 234 // 2 + 8 + 64 + 32 + 128]
let filtered = cars.filter(car => (car.bin_specs & bin_preferences) === car.bin_specs)
console.log(filtered);
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744257557a4565472.html
评论列表(0条)