结合数组和字典属性的数据类型

Posted

技术标签:

【中文标题】结合数组和字典属性的数据类型【英文标题】:Data type that combines properties of array and dictionary 【发布时间】:2014-04-26 01:32:50 【问题描述】:

在我的项目中,我有一组对象(类实例),我需要通过键访问它们,但也需要按给定顺序进行排序和访问。我应该如何存储这些对象?

我可以同时拥有 Array 和 Dictionary 并手动使它们保持同步,但这是次优的(例如,当您想要删除一个对象时,您需要首先在 Array 中找到它)。

//dictionary properties
objectsDictionary[object.id] = object;

//array properties 
objectsArray.sort(function)

有没有一种数据结构结合了 Array 和 Dictionary 的属性?这样的结构可以在内部不遍历数组的情况下进行调制吗?

我使用的语言是 TypeScript,但答案可能更笼统。

【问题讨论】:

顺序只能用数组来保证。您可以将其存储在字典中并根据键计算排序顺序 你的想法差不多了;带有 keyspropertiesObject - keysArray 带有 indicies 我认为您不会找到具有所有这些属性的神奇结构。以Backbone.Collection 的实现为例,它使用数组this.models 以及用于键查找的对象this._byId 我只是想确保我没有错过什么大事。同时使用数组和对象的问题就像我说的那样,如果你想删除一个对象,遍历数组的丑陋。 【参考方案1】:

您可以使用这样的构造函数自己实现它。请注意,大多数方法必须在 instance 上定义,因为它们使用不共享的引用。..

/* OADictionary
 *     value getItemAt    , int index
 *     value getItem      , str key
 *     void  addItem      , str key, value [, int index]
 *     void  removeItemAt , int index
 *     void  removeItem   , str key
 *     void  sort         , function comparator(key_a, key_b, val_a, val_b)
 */

function OADictionary() 
    var keys = [],
        obj = ;
    this.getItemAt = function (index) 
        return obj[keys[index]];
    ;
    this.getItem = function (key) 
        return obj[key];
    ;
    this.addItem = function (key, val, index) 
        if (obj[key]) throw new Error('key already exists: ' + key);
        obj[key] = val;
        if (index || index === 0)
            keys.splice(index, 0, key);
        else
            keys.push(key);
    ;
    this.removeItemAt = function (index) 
        delete obj[keys[index]];
        keys.splice(index, 1);
    ;
    this.removeItem = function (key) 
        delete obj[key];
        keys.splice(keys.indexOf(key), 1);
    ;
    this.sort = function (comparator) 
        var mComparator = function (key_a, key_b) 
            return comparator(key_a, key_b, obj[key_a], obj[key_b]);
        ;
        if (comparator)
            keys.sort(mComparator);
        else
            keys.sort();
    ;

现在您可以创建有序键值对

var d = new OADictionary();
d.addItem('foo', 'bar');
d.addItem('fizz', 'buzz');
d.getItem('fizz'); // "buzz"
d.getItemAt(0);    // "bar"
d.sort();
d.getItemAt(0);    // "buzz"

【讨论】:

您可能希望进一步扩展它以包含 d.keys(); // keysd.keyAt(i); // keyd.indexOfKey(key); // indexd.indexOf(val); // index (will probably require a loop) 等函数【参考方案2】:

一般而言,在 javascript 中,您不能将任意索引与同一对象上的任何其他内容结合起来并获得可预测的结果。例如:

var arrayAndDictionary = /*... something ...*/;

// Accidently malicious user data
var objects = [ id: 'sort' , id: 'length', id: 'forEach' ];

objects.forEach(object => 
    arrayAndDictionary[object.id] = object;
);

objects.sort(); // Crash.

真的,除非您 100% 控制这些 id 并且非常小心,否则您甚至不想关闭 id。你可以被Little Bobby Proto烧死:

// Collection of users on our website
var myObjects = ;
// New user named __proto__ signs up
myObjects['__proto__'] =  'userId': 'bobby' 
// Is there a user named 'userId' ?
alert(myObjects['userId']); // "bobby", not undefined

【讨论】:

【参考方案3】:

您可以尝试使用Map 对象。

可以按键访问:

Map 对象是一个简单的键/值映射

并且还按顺序迭代:

Map 对象可以按插入顺序迭代其元素

【讨论】:

这是 EcmaScript 6,据我所知,它甚至不是 TypeScript 的一部分,不是吗? PS:我等不及了! @daniel.sedlacek 不知道,我不知道打字稿:)

以上是关于结合数组和字典属性的数据类型的主要内容,如果未能解决你的问题,请参考以下文章

最佳实践? - 数组/字典作为核心数据实体属性 [关闭]

多级 JSON 缺少属性类型(字典/数组)

如何接受数据的“字典”作为自定义 .NET 属性参数?

FlutterDart的数据类型list&Map(数组和字典)

字典模型

redis数据结构之字典/哈希表