简体   繁体   English

在JavaScript中搜索数组映射的最有效方法

[英]Most efficient way to search a map of arrays in JavaScript

I have a map of arrays of numbers in JavaScript. 我有一个JavaScript数字数组的地图。 My goal is to get the key of the value that contains a certain number. 我的目标是获取包含特定数字的值的键。 I'm also open to a different data structure that might be more efficient. 我也对可能更有效的不同数据结构持开放态度。

let bookCategory = {
    "fantasy": [10064, 10066, 10071],
    "scifi": [10060, 10037, 10061],
    "history": [10001, 10003, 10004, 10005],
    "biography": [10032, 10006, 10002, 10028, 10009, 10030, 100031],
    "educational": [10025]
};

Each number will only ever appear once, but each array can contain close to a hundred numbers and it may grow substantially from there. 每个数字只会出现一次,但每个数组可以包含接近一百个数字,并且它可能会从那里大幅增长。 The arrays could be immutable as my data is static. 数组可以是不可变的,因为我的数据是静态的。

Right now I have this, but it doesn't seem terribly efficient. 现在我有这个,但它看起来效率不高。

let category;
let keys = _.keys(categories);
let theNumber = 10032;

for(let j = 0; j < keys.length; j++) {
    if(_.includes(categories[keys[j]], theNumber)) {
        category = keys[j];
        break;
    }
}

lodash library has a lot of useful functions. lodash库有很多有用的功能。 Using it, you have the following options: 使用它,您有以下选择:

1. Binary search 1.二进制搜索

Create a new structure with sorted array of numbers. 使用排序的数字数组创建一个新结构。 When looking for a number, apply a binary search. 查找数字时,应用二进制搜索。
_.sortedIndexOf() method uses binary search in an array. _.sortedIndexOf()方法在数组中使用二进制搜索。

var bookCategory = {
 "fantasy": [10064, 10066, 10071],
 "scifi": [10060, 10037, 10061],
 "history": [10001, 10003, 10004, 10005],
 "biography": [10032, 10006, 10002, 10028, 10009, 10030, 100031],
 "educational": [10025]
};

var binaryMap = _.mapValues(bookCategory, function(category) {
  return category.sort(function(num1, num2) { 
    return num1 - num2; 
  });
});

//then search using binary algorithm    
var number = 10032;
var keyForNumber = _.findKey(binaryMap, function(numbers) {
  return _.sortedIndexOf(numbers, number) !== -1;
});

keyForNumber // prints "biography"

Check the working demo . 检查工作演示

2. Create a map object 2.创建一个地图对象

Because the numbers will appear only once, it's easy to create a big hash object, where the key is the number and value is the category. 因为数字只出现一次,所以很容易创建一个大的哈希对象,其中键是数字,值是类别。 It requires a bit more memory because copies the categories string, but it works quite fast. 它需要更多的内存,因为复制类别字符串,但它的工作速度非常快。
This solution doesn't require lodash. 该解决方案不需要lodash。

var bookCategory = {
 "fantasy": [10064, 10066, 10071],
 "scifi": [10060, 10037, 10061],
 "history": [10001, 10003, 10004, 10005],
 "biography": [10032, 10006, 10002, 10028, 10009, 10030, 100031],
 "educational": [10025]
};

var map = _.reduce(bookCategory, function(result, numbers, key) {
  _.each(numbers, function(number) {
    result[number] = key;
  });
  return result;
}, {});

// or alternative without lodash
var mapAlternative = Object.keys(bookCategory).reduce(function(result, key) {
  bookCategory[key].forEach(function(number) {
    result[number] = key;
  });
  return result;
}, {});


var number = 10003;
map[number]; // prints "history"

Check the working demo . 检查工作演示

There are too many what-ifs to answer that question, the biggest one being: How often is the data going to be updated vs read . 有太多的what-ifs要回答这个问题,最大的一个是:多久将是数据updated VS read

If it is going to be read much more often, then iterate through the bookCategory first and create a sparse array/object that links the numbers back to the category. 如果要更频繁地read它,那么首先遍历bookCategory并创建一个稀疏数组/对象,将数字链接回类别。

(I'll go for object here): (我会在这里寻找对象):

// Generate this programatticly, of course.
bookCategoryLinkback = {
    10064: "fantasy",
    10066: "fantasy",
    10071: "fantasy"
};

sort the array and use binary search. 对数组进行排序并使用二进制搜索。 You can use lodash lib to do it easily. 您可以使用lodash lib轻松完成。

I suggest to use a hashtable for the numbers. 我建议使用哈希表来表示数字。

 var bookCategory = { "fantasy": [10064, 10066, 10071], "scifi": [10060, 10037, 10061], "history": [10001, 10003, 10004, 10005], "biography": [10032, 10006, 10002, 10028, 10009, 10030, 100031], "educational": [10025] }, numbers = function (data) { var r = Object.create(null); Object.keys(data).forEach(k => data[k].forEach(a => r[a] = k)); return r; }(bookCategory) document.write('<pre>' + JSON.stringify(numbers, 0, 4) + '</pre>'); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM