选择 table 数据(对象数组)JS 的高性能方法
High performance methods for selecting table data (array of objects) JS
我正在尝试优化从大型 table(对象数组)中选择数据。
我想从一行中保存多个值,然后写入 localStorage。
let customerTable = [
{
"customer": "Apple Computers",
"contact": "Steve Jobs",
"id": 1,
"city": "Cupertino"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
},
{
"customer": "Microsoft",
"contact": "Satya Nadella",
"id": 3,
"city": "Redmond"
}
]
let selectedRow = customerTable
.filter(i => { return i.customer === selectedCustomer })
.filter(i => { return i.contact === selectedContact })
let id = selectedRow
.map(a => a.id)
.filter((item, pos, self) => {return self.indexOf(item) === pos}) // Remove duplicates
let city = selectedRow
.map(a => a.city)
.filter((item, pos, self) => { return self.indexOf(item) === pos })
是否有更高效的方法从这种类型的数据模型中选择多个值?
一般来说,你希望减少你的循环次数,所以当一个循环可以达到相同的结果时,你不应该使用多个数组操作。您正在执行的操作可以优化。
let selectedRow = customerTable
.filter(i => { return i.customer === selectedCustomer })
.filter(i => { return i.contact === selectedContact });
遍历数组两次。它可以被重写为只循环遍历数组一次为
let selectedRow = customerTable
.filter(i => {return i.customer === selectedCustomer && i.contact === selectedContact});
另一个示例也利用了可以在一个循环中执行的多个数组操作。
您当前的代码将计算 selectedRow
作为数组中所有匹配的客户和联系人对,并且 city
和 id
也是唯一城市和 ID 的数组。这可以在单个循环中执行为。
// using Set for performance as suggested by @HMR
let selectedRows = [], cities = new Set(), ids = new Set();
for (let i = 0; i = customerTable.length; i++) {
if (customerTable[i].customer === selectedCustomer && customerTable[i].contact === selectedContact) {
selectedRows.push(customerTable[i]);
// include uniqueness contraint on cities and ids
cities.add(customerTable[i].city);
ids.add(customerTable[i].id);
}
}
根据您获取数据的位置(如果您可以重构数据),您可以使用以客户、联系人或两者的某种组合作为键的哈希图(对象)在此搜索中获得更好的性能。
过滤器看起来不错;但是你可以 .
优化获取唯一值
let id = [...selectedRow.reduce(
(result,item)=>result.add(item.id)
,new Set()
)]
或者正如 Jonas 指出的那样(所以你不需要 reduce):
let id = [...new Set(
selectedRow.map(item=>item.id)
)]
let customerTable = [
{
"customer": "Apple Computers",
"contact": "Steve Jobs",
"id": 1,
"city": "Cupertino"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
}
]
let selectedCustomer = "Microsoft";
let selectedContact = "Bill Gates";
// [[id], [city]]
let results = customerTable.reduce((_i, _j) => {
if(!(_j.customer === selectedCustomer && _j.contact === selectedContact)) return _i;
_i[0].push(_j.id);
_i[1].push(_j.city);
return _i;
}, [[], []])
.map((v) => v.filter((i, j, a) => a.indexOf(i) === j));
last .map
, .filter
用于删除重复项(如有问题),如果您确定不会有任何重复项,您可以删除此行,
如果不需要其他过滤且没有重复,代码将如下所示
let results = customerTable.reduce((_i, _j) => {
if(!(_j.customer === selectedCustomer && _j.contact === selectedContact)) return _i;
_i[0] = _j.id;
_i[1] = _j.city;
return _i;
}, [-1, ""])
首先,为什么你有重复的ID? ID 的意义不在于它们是唯一的吗?
除了优化实际代码外,您还可以优化过滤的数据;如评论中所述,搜索短列表比搜索长列表更快。
因此,如果与您对数据进行的搜索相比,您的数组更改相对较少,则可能值得创建一个或多个索引。这可能很简单:
let ixCustomer = new Map();
const ixCustomerKey = item => item.customer.charAt(0).toLowerCase();
const add = (index, key, value) => {
if(index.has(key)) index.get(key).push(value)
else index.set(key, [value]));
}
for(let item of customerTable){
add(ixCustomer, ixCustomerKey(item), item);
}
这样一来,如果您进行搜索,则不必搜索 customerTable
,而只需搜索一个子集,如果您选择正确的数据索引方式,该子集应该比原始数组小得多。
let id = new Set();
let city = new Set();
let arr = ixCustomer.get(ixCustomerKey(selectedCustomer)) || [];
for(let item of arr){
if(item.customer !== selectedCustomer || item.company !== selectedCompany) continue;
id.add(item.id);
city.add(item.city);
}
但是您需要知道对于您的数据和 use-case,这种开销是否值得。
我正在尝试优化从大型 table(对象数组)中选择数据。
我想从一行中保存多个值,然后写入 localStorage。
let customerTable = [
{
"customer": "Apple Computers",
"contact": "Steve Jobs",
"id": 1,
"city": "Cupertino"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
},
{
"customer": "Microsoft",
"contact": "Satya Nadella",
"id": 3,
"city": "Redmond"
}
]
let selectedRow = customerTable
.filter(i => { return i.customer === selectedCustomer })
.filter(i => { return i.contact === selectedContact })
let id = selectedRow
.map(a => a.id)
.filter((item, pos, self) => {return self.indexOf(item) === pos}) // Remove duplicates
let city = selectedRow
.map(a => a.city)
.filter((item, pos, self) => { return self.indexOf(item) === pos })
是否有更高效的方法从这种类型的数据模型中选择多个值?
一般来说,你希望减少你的循环次数,所以当一个循环可以达到相同的结果时,你不应该使用多个数组操作。您正在执行的操作可以优化。
let selectedRow = customerTable
.filter(i => { return i.customer === selectedCustomer })
.filter(i => { return i.contact === selectedContact });
遍历数组两次。它可以被重写为只循环遍历数组一次为
let selectedRow = customerTable
.filter(i => {return i.customer === selectedCustomer && i.contact === selectedContact});
另一个示例也利用了可以在一个循环中执行的多个数组操作。
您当前的代码将计算 selectedRow
作为数组中所有匹配的客户和联系人对,并且 city
和 id
也是唯一城市和 ID 的数组。这可以在单个循环中执行为。
// using Set for performance as suggested by @HMR
let selectedRows = [], cities = new Set(), ids = new Set();
for (let i = 0; i = customerTable.length; i++) {
if (customerTable[i].customer === selectedCustomer && customerTable[i].contact === selectedContact) {
selectedRows.push(customerTable[i]);
// include uniqueness contraint on cities and ids
cities.add(customerTable[i].city);
ids.add(customerTable[i].id);
}
}
根据您获取数据的位置(如果您可以重构数据),您可以使用以客户、联系人或两者的某种组合作为键的哈希图(对象)在此搜索中获得更好的性能。
过滤器看起来不错;但是你可以
let id = [...selectedRow.reduce(
(result,item)=>result.add(item.id)
,new Set()
)]
或者正如 Jonas 指出的那样(所以你不需要 reduce):
let id = [...new Set(
selectedRow.map(item=>item.id)
)]
let customerTable = [
{
"customer": "Apple Computers",
"contact": "Steve Jobs",
"id": 1,
"city": "Cupertino"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
},
{
"customer": "Microsoft",
"contact": "Bill Gates",
"id": 2,
"city": "Redmond"
}
]
let selectedCustomer = "Microsoft";
let selectedContact = "Bill Gates";
// [[id], [city]]
let results = customerTable.reduce((_i, _j) => {
if(!(_j.customer === selectedCustomer && _j.contact === selectedContact)) return _i;
_i[0].push(_j.id);
_i[1].push(_j.city);
return _i;
}, [[], []])
.map((v) => v.filter((i, j, a) => a.indexOf(i) === j));
last .map
, .filter
用于删除重复项(如有问题),如果您确定不会有任何重复项,您可以删除此行,
如果不需要其他过滤且没有重复,代码将如下所示
let results = customerTable.reduce((_i, _j) => {
if(!(_j.customer === selectedCustomer && _j.contact === selectedContact)) return _i;
_i[0] = _j.id;
_i[1] = _j.city;
return _i;
}, [-1, ""])
首先,为什么你有重复的ID? ID 的意义不在于它们是唯一的吗?
除了优化实际代码外,您还可以优化过滤的数据;如评论中所述,搜索短列表比搜索长列表更快。
因此,如果与您对数据进行的搜索相比,您的数组更改相对较少,则可能值得创建一个或多个索引。这可能很简单:
let ixCustomer = new Map();
const ixCustomerKey = item => item.customer.charAt(0).toLowerCase();
const add = (index, key, value) => {
if(index.has(key)) index.get(key).push(value)
else index.set(key, [value]));
}
for(let item of customerTable){
add(ixCustomer, ixCustomerKey(item), item);
}
这样一来,如果您进行搜索,则不必搜索 customerTable
,而只需搜索一个子集,如果您选择正确的数据索引方式,该子集应该比原始数组小得多。
let id = new Set();
let city = new Set();
let arr = ixCustomer.get(ixCustomerKey(selectedCustomer)) || [];
for(let item of arr){
if(item.customer !== selectedCustomer || item.company !== selectedCompany) continue;
id.add(item.id);
city.add(item.city);
}
但是您需要知道对于您的数据和 use-case,这种开销是否值得。