javascript (ES6): 还有比 "for loops" 更有效的方法吗?
javascript (ES6): any more efficient way than "for loops"?
这不是重复的。请看我下面的评论!
有人知道比 ES6 中的 for 循环 更有效的解决方案吗?
下面是我写的,缺乏表现力。有什么改进的想法吗?非常感谢。
基本上我有一个关于汽车的对象和一个关于用户偏好的数组。预期的行为是将所有相关的汽车名称推入一个数组。
用户可以提供任意数量的偏好。如果首选项中提到了所有规格,则应仅推送汽车名称。因此一些偏好将是 "leftovers".
出于这个原因,在以下示例中出现了本田,但没有出现宝马,这是预期的(但行为非常缓慢)。
// 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()
您无法真正避免查看每辆车,也无法避免查看汽车的每个规格,因为您想测试每一个。您可以通过使用 Set 避免每次都遍历首选项。
所以这可能会或可能不会更快,但它 更简单 更容易理解,因为代码几乎读起来像英语:过滤汽车,其中每个规格都在首选项中:
// 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)
-- 编辑--
使用 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);
至少有一个循环无法逃脱。您总是必须遍历所有汽车,无论是使用 for... 还是使用 array.filter() 等其他结构。但是还有另一种获得性能的方法。您可以使用位掩码。这将需要更改汽车对象的数据结构,以便每辆汽车都已经包含与其规格对应的位掩码,并且当用户选择所需的规格时,同样应添加规格代码。
(但是,我怀疑这可能会带来太多麻烦而收效甚微。)
// 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);
这不是重复的。请看我下面的评论!
有人知道比 ES6 中的 for 循环 更有效的解决方案吗?
下面是我写的,缺乏表现力。有什么改进的想法吗?非常感谢。
基本上我有一个关于汽车的对象和一个关于用户偏好的数组。预期的行为是将所有相关的汽车名称推入一个数组。
用户可以提供任意数量的偏好。如果首选项中提到了所有规格,则应仅推送汽车名称。因此一些偏好将是 "leftovers".
出于这个原因,在以下示例中出现了本田,但没有出现宝马,这是预期的(但行为非常缓慢)。
// 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()
您无法真正避免查看每辆车,也无法避免查看汽车的每个规格,因为您想测试每一个。您可以通过使用 Set 避免每次都遍历首选项。
所以这可能会或可能不会更快,但它 更简单 更容易理解,因为代码几乎读起来像英语:过滤汽车,其中每个规格都在首选项中:
// 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)
-- 编辑--
使用 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);
至少有一个循环无法逃脱。您总是必须遍历所有汽车,无论是使用 for... 还是使用 array.filter() 等其他结构。但是还有另一种获得性能的方法。您可以使用位掩码。这将需要更改汽车对象的数据结构,以便每辆汽车都已经包含与其规格对应的位掩码,并且当用户选择所需的规格时,同样应添加规格代码。 (但是,我怀疑这可能会带来太多麻烦而收效甚微。)
// 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);