我正在Nodejs中构建一些程序,该程序需要跟踪在内存中的大量用户。此外,我将具有按ID过滤用户的功能。代码看起来像这样:
const users = [
{
id: 1,
name: 'John',
friends: [3, 6, 8]
},
{
id: 2,
name: 'Mark',
friends: [567, 23]
}
]
function getUserById(userId) {
const user = users.filter(user => user.id === userId);
return user[0];
}
问题是,此版本通常是否更快(每个键都是用户ID):
const users = {
1: {
id: 1,
name: 'John',
friends: [3, 6, 8]
},
2: {
id: 2,
name: 'Mark',
friends: [567, 23]
}
}
function getUserById(userId) {
return users[userId];
}
我的直觉是字典更快。事实是什么?
答案 0 :(得分:2)
不能保证对象中的键查找时间。它也可能是O(n),但是如果您多次动态查找键,大多数引擎会将其朝O(1)优化。过滤数组的时间为O(n),.find()
平均快两倍:
return users.find(user => user.id === userId);
现在,唯一保证 O(1)查找的数据结构是Map
:
const userMap = new Map(users.map(u => [u.id, u]));
console.log(userMap.get("test"));
但是,如果您打算大规模执行此操作(100k很大),我宁愿将该任务移至数据库,因为它已针对这些任务进行了优化。 MongoDB会很容易采用,Redis会非常快,还有很多其他东西。
答案 1 :(得分:1)
我写了一个小脚本,可以将其复制粘贴到控制台上,并显示该问题的实际数据,并在实践中改变乔纳斯·威尔姆斯的答案。
function random_int_from_range(x, y) {
return (x + Math.floor(Math.random() * (y - x + 1)));
}
function generate_name(length_min, length_max) {
var letters = 'abcdefghijklmnopqrstuvwxyz';
var name_array = [];
for (var i = 0; i <= random_int_from_range(length_min, length_max); i ++) {
name_array.push(letters.charAt(Math.floor(Math.random() * letters.length +1)));
}
return name_array.join('')
}
function generate_friends_array(length_min, length_max, num_users) {
friends_array = [];
for (var i = 0; i < random_int_from_range(length_min, length_max); i++) {
friends_array.push(random_int_from_range(0, num_users - 1))
}
return friends_array
}
function generate_users_dict(num_users) {
var users = {};
for (var i = 0; i < num_users; i++) {
users[i] = {
'id': i,
'name': generate_name(4,6),
'friends': generate_friends_array(0, 20, num_users)
}
}
return users
}
function generate_users_list_from_dict(users_dict) {
var users_list = [];
for (var key in users_dict) {
users_list.push(users_dict[key]);
}
return users_list;
}
function get_diff_in_seconds_from_two_milisecond_values(early_value, late_value) {
return (late_value - early_value) / 1000
}
function get_user_by_id_from_dict(users_dict, user_id) {
return users_dict[user_id]
}
function get_user_by_id_from_list(users_list, user_id) {
const users = users_list.filter(user => user.id === user_id);
return users[0]
}
function get_time_for_retrieval_of_item_from_object(object, object_length) {
var function_names = ['get_user_by_id_from_dict', 'get_user_by_id_from_list'];
var random_id = random_int_from_range(0, object_length - 1);
var function_name = '';
if (Array.isArray(object)) {
function_name = function_names[1];
}
else {
function_name = function_names[0];
}
var time_before_retrieval = new Date().getTime();
window[function_name](object, random_id);
var time_after_retrieval = new Date().getTime();
return get_diff_in_seconds_from_two_milisecond_values(time_before_retrieval,
time_after_retrieval);
}
function test_retrieval_times(number_of_users, tests_num, object_type) {
var users_dict = generate_users_dict(number_of_users);
var users_list = generate_users_list_from_dict(users_dict);
var times_array = [];
var object = '';
if (object_type == 'dict') {
object = users_dict;
}
else {
object = users_list;
}
for (var i = 0; i < tests_num; i++) {
times_array.push(get_time_for_retrieval_of_item_from_object(object,
number_of_users));
}
return times_array;
}
function get_average_retrieval_time(object_type, number_of_users,
numbers_of_retrievals) {
var retrieval_times = test_retrieval_times(number_of_users, numbers_of_retrievals,
object_type);
var sum = 0;
for (var i = 0; i < retrieval_times.length; i++) {
sum += retrieval_times[i];
}
console.log('average retrieval time for ' + object_type + ': ' + sum /
numbers_of_retrievals);
}
var number_of_users = parseInt(prompt("Please enter object size", "1000000"));
var number_of_retrievals = parseInt(prompt("Please enter number of retrievals",
"100"));
get_average_retrieval_time('dict', number_of_users, number_of_retrievals);
get_average_retrieval_time('list', number_of_users, number_of_retrievals);
测试结果将打印到控制台。