如何在javascript中实现Map或排序集

6tr1vspr  于 2023-02-18  发布在  Java
关注(0)|答案(8)|浏览(142)

Javascript有使用数字索引["john", "Bob", "Joe"]的数组和对象,这些对象可以像关联数组或“Map”一样使用,允许对象值{"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"]) { }
xpszyzbs

xpszyzbs1#

看看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/

sxpgvts3

sxpgvts32#

在ES6中,你可以选择用sort方法扩展Map构造函数/类,该方法带有可选的比较函数(就像数组一样),sort方法将带有两个参数,每个参数都是键/值对,这样排序就可以在键或值(或两者)上进行。
sort方法将依赖于Map的记录行为,即按照插入顺序迭代条目,因此这个新方法将根据排序顺序访问条目,然后删除并立即重新插入它们。
下面是可能的情况:

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
9bfwbjaz

9bfwbjaz3#

我不知道为什么这些答案中没有一个提到内置JS类Set的存在,似乎是ES6的一个补充,也许这就是原因。
理想情况下覆盖addkeys如下...注意覆盖keys甚至不需要访问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)};

打印输出:
一、二、三
注意Set.keys()返回的不是Set中的元素,而是一个迭代器,你可以选择返回排序后的数组,但是很明显你会破坏类的"契约"。
要覆盖哪一个?取决于您的使用和Set的大小。如果您覆盖了这两个,您将重复排序活动,但在大多数情况下,这可能并不重要。
NB我建议的add函数当然很幼稚,只是一个"初稿":每次add时重建整个集合可能会非常昂贵。显然有更聪明的方法来完成这一点,方法是基于检查Set中的现有元素并使用比较函数,二叉树结构 *,或一些其它方法来确定在其中的位置以添加要添加的候选(我之所以说"候选",是因为如果已经发现存在一个"相同的"元素,即它本身,那么它将被拒绝)。
这个问题还询问了排序Map的类似安排...事实上,ES6有一个新的Map类,可以进行类似的处理...而且Set只是一个专用的Map,正如您所料。

vybvopom

vybvopom4#

通常不对对象进行排序,但如果进行排序: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

sxissh06

sxissh065#

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

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
khbbv19g

khbbv19g6#

如果您使用开源项目jinqJs,这很容易。
参见Fiddler

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

3phpmpom7#

下面是一个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());
g52tjvyc

g52tjvyc8#

https://github.com/js-sdsl/js-sdsl
Js-sdl中的OrderedMap可能会有帮助。
这是一个参照C++ STL Map实现的分类Map。

/*
 * key value
 * 1   1
 * 2   2
 * 3   3
 * Sorted by key.
 */
const mp = new OrderedMap(
    [1, 2, 3].map((element, index) => [index, element])
);
mp.setElement(1, 2);        // O(logn)
mp.eraseElementByKey(1)     // O(logn)

// custom comparison function
mp = new OrderedMap(
    [1, 2, 3].map((element, index) => [index, element]),
    (x, y) => x - y
);

// enable tree iterator index (enableIndex = true)
console.log(new OrderedMap([[0, 1], [1, 1]], undefined, true).begin(),next().index);   // 1

相关问题