如何在javascript中实现映射或排序集
How to implement a map or sorted-set in javascript
Javascript有使用数字索引["john", "Bob", "Joe"]
的数组和可以像关联数组或允许对象值{"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"]) { }
看看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/
使用ES6,您可以选择使用sort
方法扩展Map
构造函数/类,该方法采用可选的比较函数(就像数组一样)。sort
方法将采用两个参数,每个参数都是键/值对,因此可以对键或值(或两者)进行排序。
sort
方法将依赖于Maps的记录行为,即按插入顺序迭代条目。因此,这种新方法将根据排序顺序访问条目,然后删除并立即重新插入它们。
以下是它的样子:
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
我不知道为什么这些答案都没有提到内置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
中的项,而是迭代器。您可以选择返回已排序的数组,但这显然会破坏类的";合同";。
要覆盖哪一个?取决于您的使用情况和Set
的大小。如果同时覆盖这两个,则会复制排序活动,但在大多数情况下,这可能无关紧要。
NB我建议的add
函数当然是幼稚的;初稿":每次add
时重建整个集合可能非常昂贵。基于检查CCD_,或者确定的某种其他方法,其中添加要添加的候选者(我说"候选者",因为如果已经发现存在"相同"元素,即其本身,它将被拒绝)。
这个问题还询问了排序地图的类似安排。。。事实上,ES6有一个新的Map类,可以进行类似的处理。。。而且Set
只是一个专门的Map
,正如你所料。
*例如。https://github.com/Crizstian/data-structure-and-algorithms-with-ES6/tree/master/10-chapter-Binary-Tree
通常不会对对象进行排序。但如果您这样做:按属性值对JavaScript对象进行排序
如果你想对数组进行排序,比如下面的
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
也许这段代码看起来像你想要的:
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
如果你使用开源项目jinqJs它很容易。
参见Fiddler
var result = jinqJs()
.from([{"john" : 28},{ "bob": 34},{ "joe" : 4}])
.orderBy([{field: 0}])
.select();
这里是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());
https://github.com/js-sdsl/js-sdsl
Js-sdsl中的OrderedMap
可能会有所帮助。
这是一个排序映射,实现了对C++STL映射的引用。
/*
* 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
- 如何在映射数组中添加换行符
- ng映射方向备选方案
- JavaScript数组排序(函数)用于对表行进行排序,而不是排序
- 使用promise和mongoose对文档进行排序
- 无法通过数组映射绑定
- Selectize.js:如何对整数值的选项进行排序
- Javascript排序的图像弹出窗口..可以't单独弹出
- 在javascript中按映射中的值排序
- 如何在javascript中实现映射或排序集
- 按值对映射/哈希进行排序,保留键
- 挖空可拖动可排序映射克隆更改
- 如何使用 knockoutjs 映射插件对绑定到表的数据进行排序
- 在Knockout.js中,如何在映射后根据复选框字段对viewModel项进行排序
- 在ReactJS上使用Lodash对映射列表进行排序
- 在保留键的情况下,基于对象属性对映射进行排序
- 如何在不可变映射中排序(交换)项
- 如何在Angular JS中对1:1的对象映射进行排序
- 我怎样才能得到一个按"减少"的降序排序的映射/减少结果;值";价值如果也使用列表功能可以实
- 是否可以对 ES6 映射对象进行排序
- 为什么要在数组上使用排序映射.在某些情况下如何更好