英文:
JSON.stringify Map with nested Set
问题
考虑以下图形:
class Node {
constructor(value) {
this.value = value;
this.adjacents = new Set();
}
addAdjacent(node) {
this.adjacents.add(node);
}
}
class Graph {
constructor(directed = false) {
this.nodes = new Map();
this.directed = directed;
}
addVertex(value) {
const node = this.nodes.has(value);
if (node) {
return this.nodes.get(value);
}
const vertex = new Node(value);
this.nodes set(value, vertex);
return vertex;
}
addEdge(src, dest) {
let srcNode = this.nodes.get(src);
if (!srcNode) {
srcNode = this.addVertex(src);
}
let destNode = this.nodes.get(dest);
if (!destNode) {
destNode = this.addVertex(dest);
}
srcNode.addAdjacent(destNode);
if (this.directed === false) {
destNode.addAdjacent(srcNode);
}
}
}
const g1 = new Graph();
g1.addVertex("a");
g1.addVertex("b");
g1.addEdge("a", "c");
当我使用 console.log
输出图形对象 g1
时,我得到以下输出:
Graph {
nodes: Map(3) {
'a' => Node { value: 'a', adjacents: [Set] },
'b' => Node { value: 'b', adjacents: Set(0) {} },
'c' => Node { value: 'c', adjacents: [Set] }
},
directed: false
}
正如输出所示,我没有获取有关顶点的边的信息。
我尝试将 replacer
传递给 JSON.stringify
如下,但会导致栈溢出错误。
console.log(
JSON.stringify(
Object.fromEntries(g1.nodes),
(_key, value) =>
value.adjacents instanceof Set ? [...value.adjacents] : value,
2
)
);
错误:
JSON.stringify(
^
RangeError: Maximum call stack size exceeded
at JSON.stringify (<anonymous>)
如何以更友好的格式打印图形?
英文:
Consider the following graph:
class Node {
constructor(value) {
this.value = value;
this.adjacents = new Set();
}
addAdjacent(node) {
this.adjacents.add(node);
}
}
class Graph {
constructor(directed = false) {
this.nodes = new Map();
this.directed = directed;
}
addVertex(value) {
const node = this.nodes.has(value);
if (node) {
return this.nodes.get(value);
}
const vertex = new Node(value);
this.nodes.set(value, vertex);
return vertex;
}
addEdge(src, dest) {
let srcNode = this.nodes.get(src);
if (!srcNode) {
srcNode = this.addVertex(src);
}
let destNode = this.nodes.get(dest);
if (!destNode) {
destNode = this.addVertex(dest);
}
srcNode.addAdjacent(destNode);
if (this.directed === false) {
destNode.addAdjacent(srcNode);
}
}
}
const g1 = new Graph();
g1.addVertex("a");
g1.addVertex("b");
g1.addEdge("a", "c");
When I console.log
the graph object g1
. I get the following output:
Graph {
nodes: Map(3) {
'a' => Node { value: 'a', adjacents: [Set] },
'b' => Node { value: 'b', adjacents: Set(0) {} },
'c' => Node { value: 'c', adjacents: [Set] }
},
directed: false
}
As output shows, I get no info regarding the edges of the vertices.
I tried passing replacer
to JSON.stringify
as follows, but it results in StackOverFlow error.
console.log(
JSON.stringify(
Object.fromEntries(g1.nodes),
(_key, value) =>
value.adjacents instanceof Set ? [...value.adjacents] : value,
2
)
);
Error:
JSON.stringify(
^
RangeError: Maximum call stack size exceeded
at JSON.stringify (<anonymous>)
How can I print the graph in a more friendly format?
答案1
得分: 3
-
两个问题:
Map
和Set
都无法直接序列化为 JSON。- 您的数据结构是循环的,因此无法进行序列化;节点 a 与节点 c 相邻,节点 c 与节点 a 相邻。尝试将其序列化为扁平结构将需要无限的存储空间。
我建议在您的类中添加一个 toJSON() 方法来辅助序列化。在这里,无法序列化的数据结构可以转换为简单的数据结构,循环引用可以被解除。
例如:
class Node {
constructor(value) {
this.value = value;
this.adjacents = new Set();
}
addAdjacent(node) {
this.adjacents.add(node);
}
toJSON() {
return {
...this,
// plain array with scalar values
adjacents: [...this.adjacents].map(({ value }) => value),
};
}
}
class Graph {
constructor(directed = false) {
this.nodes = new Map();
this.directed = directed;
}
addVertex(value) {
const node = this.nodes.has(value);
if (node) {
return this.nodes.get(value);
}
const vertex = new Node(value);
this.nodes.set(value, vertex);
return vertex;
}
addEdge(src, dest) {
let srcNode = this.nodes.get(src);
if (!srcNode) {
srcNode = this.addVertex(src);
}
let destNode = this.nodes.get(dest);
if (!destNode) {
destNode = this.addVertex(dest);
}
srcNode.addAdjacent(destNode);
if (this.directed === false) {
destNode.addAdjacent(srcNode);
}
}
toJSON() {
return {
...this,
// reduce the Map entries to a simple object
nodes: Object.fromEntries(this.nodes),
};
}
}
const g1 = new Graph();
g1.addVertex("a");
g1.addVertex("b");
g1.addEdge("a", "c");
console.log(JSON.stringify(g1, null, 2));
这是您提供的代码部分的翻译。
<details>
<summary>英文:</summary>
There's two issues here...
1. Both `Map` and `Set` do not serialise directly to JSON
2. Your data structure is cyclic and therefore cannot be serialised; node _a_ is adjacent to node _c_ and node _c_ is adjacent to node _a_. Attempting to serialise this to a flat structure would require infinite storage.
I would recommend adding a [toJSON()][1] method to your classes to aid in the serialisation. There, unserialisable data structures can be converted to simple ones and cyclic references can be broken.
For example
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
class Node {
constructor(value) {
this.value = value;
this.adjacents = new Set();
}
addAdjacent(node) {
this.adjacents.add(node);
}
toJSON() {
return {
...this,
// plain array with scalar values
adjacents: [...this.adjacents].map(({ value }) => value),
};
}
}
class Graph {
constructor(directed = false) {
this.nodes = new Map();
this.directed = directed;
}
addVertex(value) {
const node = this.nodes.has(value);
if (node) {
return this.nodes.get(value);
}
const vertex = new Node(value);
this.nodes.set(value, vertex);
return vertex;
}
addEdge(src, dest) {
let srcNode = this.nodes.get(src);
if (!srcNode) {
srcNode = this.addVertex(src);
}
let destNode = this.nodes.get(dest);
if (!destNode) {
destNode = this.addVertex(dest);
}
srcNode.addAdjacent(destNode);
if (this.directed === false) {
destNode.addAdjacent(srcNode);
}
}
toJSON() {
return {
...this,
// reduce the Map entries to a simple object
nodes: Object.fromEntries(this.nodes),
};
}
}
const g1 = new Graph();
g1.addVertex("a");
g1.addVertex("b");
g1.addEdge("a", "c");
console.log(JSON.stringify(g1, null, 2));
<!-- language: lang-css -->
.as-console-wrapper { max-height: 100% !important; }
<!-- end snippet -->
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论