2016-04-21 44 views
3

我有一個JavaScript數組數組的地圖。我的目標是獲得包含特定數字的值的關鍵字。我也打開了一個可能更有效的不同數據結構。在JavaScript中搜索數組映射的最有效方法

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] 
}; 

每個數字將只出現一次,但每個數組可能包含接近一百個數字,它可能會從那裏大幅增長。由於我的數據是靜態的,數組可能是不可變的。

現在我有這個,但它似乎不是非常有效。

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; 
    } 
} 
+0

應該是什麼'10001'和'300'是輸出? –

+0

@SalvadorDali這些數字不在任何數組中,因此類別將保持「未定義」。 – diplosaurus

+1

如果這些不同 - 創建一個從值到類別的映射。 – zerkms

回答

1

lodash庫有很多有用的功能。使用它,您有以下選擇:

1.二進制搜索

創建數字排序數組新的結構。在查找數字時,應用二進制搜索。
_.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" 

檢查工作demo

2.創建一個映射對象

因爲數字將只出現一次,可以很容易地創建一個大的哈希對象,這裏的關鍵是數量和價值的範疇。它需要更多的內存,因爲複製類別字符串,但它工作得非常快。
此解決方案不需要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" 

檢查工作demo

+0

第二個命題不需要Lodash。 – oldergod

0

有太多的what-ifs回答這個問題,最大的一個是:多久將是updated VS read數據。

如果要更頻繁地使用read,則首先遍歷bookCategory,然後創建一個稀疏數組/對象,將數字鏈接回該類別。

(我會去這裏對象):

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

我的數組完全是靜態的。如果我使用「不可變」的東西,我可以完全凍結它們。根本沒有更新。 – diplosaurus

+0

然後我會使用一個循環,類似於你所擁有的,並且只是像上面展示的那樣創建一個新的反向引用對象。 –

0

排序的數組,並使用二進制搜索。您可以使用lodash lib輕鬆完成。

+1

排序花費的時間不會比僅僅遍歷它們尋找答案更長嗎?或者比我想象的要快。 – diplosaurus

+0

@diplosaurus我們不知道你在想什麼。 – zerkms

0

我建議使用散列表的數字。

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>');

相關問題