如何在javascript中实现地图或排序集

时间:2015-04-01 14:32:51

标签: javascript arrays sorting object

Javascript包含使用数字索引["john", "Bob", "Joe"]的数组和可以像关联数组一样使用的对象或者#34; maps"允许对象值{"john" : 28, "bob": 34, "joe" : 4}的字符串键。

在PHP中,很容易 A)按值排序(同时保持键)和 B)测试关联数组中是否存在值

$array = ["john" => 28, "bob" => 34, "joe" => 4];

asort($array); // ["joe" => 4, "john" => 28, "bob" => 34];

if(isset($array["will"])) { }

您如何在Javascript中实现此功能?

这是加权列表或有序集合等常见需求,您需要在数据结构中保留一个值的副本(如标记名称),并保留加权值。

这是我迄今为止最好的:

function getSortedKeys(obj) {
    var keys = Object.keys(obj);
    keys = keys.sort(function(a,b){return obj[a]-obj[b]});

    var map = {};
    for (var i = keys.length - 1; i >= 0; i--) {
      map[keys[i]] = obj[keys[i]];
    };

    return map;
}

var list = {"john" : 28, "bob": 34, "joe" : 4};
list = getSortedKeys(list);
if(list["will"]) { }

7 个答案:

答案 0 :(得分:1)

关注this answer by Luke Schafer我想我可能已经找到了一种更好的方法来扩展Object.prototype来处理这个问题:

// Sort by value while keeping index
Object.prototype.iterateSorted = function(worker, limit)
{
    var keys = Object.keys(this), self = this;
    keys.sort(function(a,b){return self[b] - self[a]});

    if(limit) {
        limit = Math.min(keys.length, limit);
    }

    limit = limit || keys.length;
    for (var i = 0; i < limit; i++) {
        worker(keys[i], this[keys[i]]);
    }
};

var myObj = { e:5, c:3, a:1, b:2, d:4, z:1};

myObj.iterateSorted(function(key, value) {
    console.log("key", key, "value", value)
}, 3);

http://jsfiddle.net/Xeoncross/kq3gbwgh/

答案 1 :(得分:1)

使用ES6,您可以选择使用Map方法扩展sort构造函数/类,该方法采用可选的比较函数(就像数组一样)。 sort方法将采用两个参数,每个参数都是键/值对,以便排序可以在键或值(或两者)上发生。

sort方法将依赖于Google的记录行为,即按插入顺序迭代条目。因此,这个新方法将根据排序顺序访问条目,然后删除并立即重新插入它们。

以下是这样的看法:

class SortableMap extends Map {
    sort(cmp = (a, b) => a[0].localeCompare(b[0])) {
        for (const [key, value] of [...this.entries()].sort(cmp)) {
            this.delete(key);
            this.set(key, value); // New keys are added at the end of the order
        }
    }
}
// Demo
const mp = new SortableMap([[3, "three"],[1, "one"],[2, "two"]]);
console.log("Before: ", JSON.stringify([...mp])); // Before
mp.sort( (a, b) => a[0] - b[0] ); // Custom compare function: sort numerical keys
console.log(" After: ", JSON.stringify([...mp])); // After

答案 2 :(得分:0)

您通常不会对对象进行排序。但如果你这样做:Sorting JavaScript Object by property value

如果要对数组进行排序,请说明以下内容

var arraylist = [{"john" : 28},{ "bob": 34},{ "joe" : 4}];

您始终可以使用Array.prototype.sort功能。 资料来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

答案 3 :(得分:0)

也许这段代码看起来像你想要的那样:

Object.prototype.asort = function(){
    var retVal = {};
    var self = this;
    var keys = Object.keys(this);
    keys = keys.sort(function(a,b){return self[a] - self[b]});
    for (var i = 0; i < keys.length; i++) {
        retVal[keys[i]] = this[keys[i]];
    }
    return retVal;
}
var map = {"john" : 28, "bob": 34, "joe" : 4}
var sortedMap = map.asort();//sortedMap["will"]: undefined

答案 4 :(得分:0)

如果您使用开源项目jinqJs那么简单。

请参阅Fiddler

var result = jinqJs()
                .from([{"john" : 28},{ "bob": 34},{ "joe" : 4}])
                .orderBy([{field: 0}])
                .select();

答案 5 :(得分:0)

我不确定为什么这些答案都没有提到内置JS类Set的存在。似乎是ES6的补充,也许这就是原因。

理想情况下覆盖以下add keys ...覆盖keys的NB甚至不需要访问Set对象的原型。当然,您可以为整个Set类覆盖这些方法。或者创建一个子类SortedSet

  const mySet = new Set();

  const mySetProto = Object.getPrototypeOf( mySet );
  const addOverride = function( newObj ){
    const arr = Array.from( this );
    arr.add( newObj );
    arr.sort(); // or arr.sort( function( a, b )... )
    this.clear();
    for( let item of arr ){
      mySetProto.add.call( this, item );
    }
  }
  mySet.add = addOverride;

  const keysOverride = function(){
    const arr = Array.from( this );
    arr.sort(); // or arr.sort( function( a, b )... )
    return arr[Symbol.iterator]();
  }
  mySet.keys = keysOverride;

用法:

mySet.add( 3 ); mySet.add( 2 ); mySet.add( 1 ); mySet.add( 2 );
for( let item of mySet.keys() ){ console.log( item ) };

打印出来:

  

1 ... 2 ... 3

NB Set.keys()不返回Set中的项目,而是迭代器。您可以选择返回已排序的数组,但您显然会违反课程&#34;合同&#34;。

要覆盖哪一个?取决于您的使用情况和Set的大小。如果你覆盖两者,你将复制排序活动,但在大多数情况下,它可能不重要。

注意我建议的add功能当然是天真的,第一个草稿&#34;:每次add成本非常高时重建整套。基于检查Set中的现有元素并使用比较函数,二叉树结构*或其他方法确定其中的 where ,显然有更聪明的方法。添加候选者以进行添加(我说&#34;候选人&#34;因为如果已经发现&#34;相同的&#34;元素本身已被发现,它将被拒绝。)

这个问题还询问有关排序地图的类似安排......事实上,事实证明ES6有一个新的Map类,它有助于类似的处理...以及Set正如您所料,它只是一个专门的Map

*例如https://github.com/Crizstian/data-structure-and-algorithms-with-ES6/tree/master/10-chapter-Binary-Tree

答案 6 :(得分:0)

这是OrderedMap的实现。 使用功能get()set()将键值对提取或推入OrderedMap。 它在内部使用数组维护顺序。

class OrderedMap {
  constructor() {
    this.arr = [];
    return this;
  }
  get(key) {
    for(let i=0;i<this.arr.length;i++) {
      if(this.arr[i].key === key) {
        return this.arr[i].value;
      }
    }
    return undefined;
  }

  set(key, value) {
    for(let i=0;i<this.arr.length;i++) {
      if(this.arr[i].key === key) {
        this.arr[i].value = value;
        return;
      }
    }
    this.arr.push({key, value})
  }

  values() {
    return this.arr;
  }
}

let m = new OrderedMap();
m.set('b', 60)
m.set('a', 10)
m.set('c', 20)
m.set('d', 89)

console.log(m.get('a'));

console.log(m.values());