JSON.stringify嵌套了Set的Map

huangapple go评论74阅读模式
英文:

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

  1. 两个问题:

    1. MapSet 都无法直接序列化为 JSON。
    2. 您的数据结构是循环的,因此无法进行序列化;节点 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&#39;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
&lt;!-- begin snippet: js hide: false console: true babel: false --&gt;
&lt;!-- language: lang-js --&gt;
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 }) =&gt; 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(&quot;a&quot;);
g1.addVertex(&quot;b&quot;);
g1.addEdge(&quot;a&quot;, &quot;c&quot;);
console.log(JSON.stringify(g1, null, 2));
&lt;!-- language: lang-css --&gt;
.as-console-wrapper { max-height: 100% !important; }
&lt;!-- end snippet --&gt;
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description
</details>

huangapple
  • 本文由 发表于 2023年6月8日 08:36:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427919.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定