1

我有一个对象数组。数组的键是用 .push() 自动生成的。一些对象可能会从数组中删除delete array[index];。数组可能包含 0 到 10K+ 个条目。

这是声明和一些逻辑:

var allClients = [];

someFunction(client) {
    allClients.push(client);

    var callbackFunction = function() {
        var index = allClients.indexOf(client);
        try {
            delete allClients[index];
        } catch (err) {
            console.error(err);
        }
    }
}

function getClientsMeetingCriteria(some_unique_id) {
    var filteredClients = allClients.filter(function(client) {
        return client.id_list.indexOf(some_unique_id) > -1;
    });
    return filteredClients;
}

现在上面的代码(它是 IRL 的非常简化的版本)适用于 100-300 个客户端,但是对于 500+ 的目的来说它变得太慢了。问题是它getClientsMeetingCriteria()可能每秒被异步调用 10 次。我需要设置缓存some_unique_id作为键。我有缓存代码,但我不知道如何将这些数据存储在其中。想象一下:

  1. client = {id:1, id_list='123;124;'}被添加到clients[]
  2. getClientsMeetingCriteria('123')返回[client {id:1...}]并缓存响应
  3. delete client[0]被调用并且客户端被从clients[]
  4. getClientsMeetingCriteria('123')再次调用并返回 cached [client {id:1...}],但该条目不再在clients[]

我知道 JS 在这种情况下是按值传递的(return filteredClients)。到目前为止,我想出了这个:我实际上可以遍历数组getClientsMeetingCriteria()并找到匹配客户端的索引。我将一个数组与它们(索引)放在some_unique_id. 我还保留了一个使用 client_ids 索引的数组,其中数据是缓存的some_unique_id引用客户端 ID 列表。在调用之前delete allClients[index],我获取数组条目index并因此获取应该刷新的缓存键列表('some_unique_id')。这似乎是一个很大的开销,但与每 100 毫秒循环通过 1K 个对象相比,这算不了什么......

你能想出更好的解决方案吗?有没有办法制作一个指向最新的数组条目(索引)的链接对象 - 换句话说,当索引被删除时刷新(变为空)?类似于迭代器的东西。

PS我也意识到我可以从缓存中加载客户端ID列表并检查索引是否存在,但这并不能解决添加具有匹配“some_unique_id”的新客户端的问题。

4

1 回答 1

1

数组是错误的数据结构。使用一些对象并预先设置索引,您根本不需要搜索

我将假设id每个客户的财产都是独一无二的。如果不是这样,请告诉我。

而且我要冒昧地使用getClientsMeetingCriteria()find下面代码中的方法)。我将返回一个包含这些客户端的对象,而不是返回一个客户端数组。这主要是为了展示一个重要的观点:您实际上可以编写此代码,因此此检索是即时的。整个函数体很简单:

        return criteria[criterion] || {};

如果您也需要一个简单的数组(并且仍然非常快),那么我们将回到这个问题。

将此代码粘贴到您的 Chrome 或 Firebug 控制台并执行它:

// Return a boolean telling if an object is empty (has no properties)
function isEmpty( object ) {
    for( var name in object ) {
        return false;
    }
    return true;
}

// An object that keeps track of clients and criteria (id_list)
function Clients() {

    // An object containing all of the clients that have been added
    // using clients.add(client). The client.id is the property name,
    // and the client object is the property value. So:
    // clients[clientID] is a client object with the given client.id
    var clients = {};

    // An object containing every unique criterion ID. The criterion ID
    // is the property name, and the property value is an object
    // containing every client that has this criterion ID in its id_list
    // property. So:
    // criteria[criterionID] is an object containing clients
    // criteria[criterionID][clientID] is a client with that criterion
    var criteria = {};

    // Internal function to split an id_list and iterate over it
    function eachCriterion( client, callback ) {
        var ids = client.id_list.split(';');
        for( var i = 0, n = ids.length;  i < n;  ++i ) {
            callback( ids[i] );
        }
    }

    // Add a client
    this.add = function( client ) {
        if( clients[client.id] ) {
            // already exists, return or error?
        }
        clients[client.id] = client;
        eachCriterion( client, function( id ) {
            if( ! criteria[id] ) {
                criteria[id] = {}
            }
            criteria[id][client.id] = client;
        });
    };

    // Remove a client
    this.remove = function( client ) {
        delete clients[client.id];
        eachCriterion( client, function( id ) {
            delete criteria[id][client.id];
            if( isEmpty(criteria[id]) ) {
                delete criteria[id];
            }
        });
    };

    // Return an object containing all the clients that have the given
    // criterion in their id_list property
    this.find = function( criterion ) {
        return criteria[criterion] || {};
    };
}

var clients = new Clients;

var client3 = { id:3, id_list:'10;20' };
var client1 = { id:1, id_list:'30;40;10' };
var client4 = { id:4, id_list:'40;20' };
var client5 = { id:5, id_list:'50;70' };
var client9 = { id:9, id_list:'10;70' };
var client2 = { id:2, id_list:'50;' };
var client7 = { id:7, id_list:'40;70;90' };

clients.add( client3 );
clients.add( client1 );
clients.add( client4 );
clients.add( client5 );
clients.add( client9 );
clients.add( client2 );
clients.add( client7 );

function find( id ) {
    console.log( 'Finding', id );
    console.log( JSON.stringify( clients.find(id), null, 4 ) );
}

find( '10' );
clients.remove( client3 );
find( '10' );
clients.remove( client1 );
find( '10' );
clients.remove( client9 );
find( '10' );

它将记录:

Finding 10
{
    "1": {
        "id": 1,
        "id_list": "30;40;10"
    },
    "3": {
        "id": 3,
        "id_list": "10;20"
    },
    "9": {
        "id": 9,
        "id_list": "10;70"
    }
}
Finding 10
{
    "1": {
        "id": 1,
        "id_list": "30;40;10"
    },
    "9": {
        "id": 9,
        "id_list": "10;70"
    }
}
Finding 10
{
    "9": {
        "id": 9,
        "id_list": "10;70"
    }
}
Finding 10
{}

如果你真的需要一个数组而不是一个对象来.find()返回,你可以使用这个版本的find方法来代替(或任何类似的代码):

    this.find = function( criterion ) {
        var result = [];
        for( var id in criteria[criterion] ) {
            result.push( clients[id] );
        }
        return result;
    };
于 2013-11-12T19:03:11.520 回答