检查重复的Javascript对象
TL;DR version:我希望避免将重复的Javascript对象添加到类似对象的数组中,其中一些对象可能非常大。最好的方法是什么? 我有一个将大量JSON数据加载到Javascript数据结构中的应用程序。虽然比这要复杂一点,但假设我通过一系列AJAX请求将JSON从服务器加载到Javascript对象数组中,比如:检查重复的Javascript对象,javascript,duplicates,Javascript,Duplicates,TL;DR version:我希望避免将重复的Javascript对象添加到类似对象的数组中,其中一些对象可能非常大。最好的方法是什么? 我有一个将大量JSON数据加载到Javascript数据结构中的应用程序。虽然比这要复杂一点,但假设我通过一系列AJAX请求将JSON从服务器加载到Javascript对象数组中,比如: var myObjects = []; function processObject(o) { myObjects.push(o); } for (var x=0
var myObjects = [];
function processObject(o) {
myObjects.push(o);
}
for (var x=0; x<1000; x++) {
$.getJSON('/new_object.json', processObject);
}
但是我担心在myHashMap
中有可能是200 kb长的属性名。因此,我的问题是:
- 对于这个问题,有没有比hashmap更好的方法
- 如果没有,有没有比
更好的方法为任意长度和模式的JSON对象生成哈希函数JSON.stringify
- 对象中超长属性名可能存在哪些问题
JSON.stringify()
中没有对象键顺序的差异,您必须创建一个对键进行排序的对象副本
然后,当每个新对象进入时,您将对照哈希映射检查它。如果在哈希映射中找到匹配项,则将传入对象与存储的实际对象进行比较,以查看它们是否真正重复(因为可能存在MD5哈希冲突)。这样,您就有了一个可管理的哈希表(其中只有MD5哈希)
下面是创建对象(包括嵌套对象或数组中的对象)的规范字符串表示的代码,该对象处理的对象键的顺序可能与调用JSON.stringify()不同
//执行规范化JSON.stringify()的代码,该函数用于放置对象属性
//以一致的顺序
//不允许循环引用(包含对父级引用的子级)
JSON.stringifyCanonical=函数(obj){
//与browser或node.js兼容
var Set=typeof window==“object”?window.Set:global.Set;
//可怜的男人
if(字体设置!=“功能”){
集合=功能{
若有(s){
this.data=s.data.slice();
}否则{
这个.data=[];
}
};
Set.prototype={
添加:功能(项目){
此.data.push(项目);
},
has:功能(项目){
返回此.data.indexOf(项)!=-1;
}
};
}
函数顺序键(对象、父对象){
if(对象类型!=“对象”){
抛出新错误(“orderKeys()需要对象类型”);
}
var集合=新集合(父集合);
如果(设置有(obj)){
抛出新错误(“stringifyCanonical()中的循环对象”);
}
集合。添加(obj);
var tempObj,项目,i;
if(数组isArray(obj)){
//无需重新订购阵列
//但是需要检查它是否有需要排序的嵌入对象
tempObj=[];
对于(i=0;i
算法
var myHashMap = {};
function processObject(o) {
var stringifiedCandidate = JSON.stringifyCanonical(o);
var hash = CreateMD5(stringifiedCandidate);
var list = [], found = false;
// is it in the hashmap?
if (!myHashMap[hash] {
// not in the hash table, so it's a unique object
myObjects.push(o);
list.push(myObjects.length - 1); // put a reference to the object with this hash value in the list
myHashMap[hash] = list; // store the list in the hash table for future comparisons
} else {
// the hash does exist in the hash table, check for an exact object match to see if it's really a duplicate
list = myHashMap[hash]; // get the list of other object indexes with this hash value
// loop through the list
for (var i = 0; i < list.length; i++) {
if (stringifiedCandidate === JSON.stringifyCanonical(myObjects[list[i]])) {
found = true; // found an exact object match
break;
}
}
// if not found, it's not an exact duplicate, even though there was a hash match
if (!found) {
myObjects.push(o);
myHashMap[hash].push(myObjects.length - 1);
}
}
}
var myHashMap={};
函数processObject(o){
var stringifiedCandidate=JSON.stringificanonical(o);
var hash=CreateMD5(stringifiedCandidate);
var list=[],found=false;
//它在hashmap中吗?
如果(!myHashMap[hash]{
//不在哈希表中,因此它是唯一的对象
肌对象推(o);
list.push(myObjects.length-1);//在列表中放置对具有此哈希值的对象的引用
myHashMap[hash]=list;//将列表存储在哈希表中以备将来比较
}否则{
//哈希表中确实存在哈希,请检查是否存在精确的对象匹配,以查看它是否真的是重复的
list=myHashMap[hash];//使用此哈希值获取其他对象索引的列表
//循环浏览列表
对于(变量i=0;i
jsonStringifyCanonical()
的测试用例如下:
{foo:1,bar:2}
和{bar:2,foo:1}
作为对象而不是字符串是相等的getJSON
而是使用$。
// Code to do a canonical JSON.stringify() that puts object properties
// in a consistent order
// Does not allow circular references (child containing reference to parent)
JSON.stringifyCanonical = function(obj) {
// compatible with either browser or node.js
var Set = typeof window === "object" ? window.Set : global.Set;
// poor man's Set polyfill
if (typeof Set !== "function") {
Set = function(s) {
if (s) {
this.data = s.data.slice();
} else {
this.data = [];
}
};
Set.prototype = {
add: function(item) {
this.data.push(item);
},
has: function(item) {
return this.data.indexOf(item) !== -1;
}
};
}
function orderKeys(obj, parents) {
if (typeof obj !== "object") {
throw new Error("orderKeys() expects object type");
}
var set = new Set(parents);
if (set.has(obj)) {
throw new Error("circular object in stringifyCanonical()");
}
set.add(obj);
var tempObj, item, i;
if (Array.isArray(obj)) {
// no need to re-order an array
// but need to check it for embedded objects that need to be ordered
tempObj = [];
for (i = 0; i < obj.length; i++) {
item = obj[i];
if (typeof item === "object") {
tempObj[i] = orderKeys(item, set);
} else {
tempObj[i] = item;
}
}
} else {
tempObj = {};
// get keys, sort them and build new object
Object.keys(obj).sort().forEach(function(item) {
if (typeof obj[item] === "object") {
tempObj[item] = orderKeys(obj[item], set);
} else {
tempObj[item] = obj[item];
}
});
}
return tempObj;
}
return JSON.stringify(orderKeys(obj));
}
var myHashMap = {};
function processObject(o) {
var stringifiedCandidate = JSON.stringifyCanonical(o);
var hash = CreateMD5(stringifiedCandidate);
var list = [], found = false;
// is it in the hashmap?
if (!myHashMap[hash] {
// not in the hash table, so it's a unique object
myObjects.push(o);
list.push(myObjects.length - 1); // put a reference to the object with this hash value in the list
myHashMap[hash] = list; // store the list in the hash table for future comparisons
} else {
// the hash does exist in the hash table, check for an exact object match to see if it's really a duplicate
list = myHashMap[hash]; // get the list of other object indexes with this hash value
// loop through the list
for (var i = 0; i < list.length; i++) {
if (stringifiedCandidate === JSON.stringifyCanonical(myObjects[list[i]])) {
found = true; // found an exact object match
break;
}
}
// if not found, it's not an exact duplicate, even though there was a hash match
if (!found) {
myObjects.push(o);
myHashMap[hash].push(myObjects.length - 1);
}
}
}