从JSON加载Vec <(String,String)>后创建Petgraph图表。

3
我正在尝试从JSON数据创建一个petgraph Graph。JSON包含图的边缘,键表示起始顶点,值是相邻顶点的列表。可以使用边缘向量生成图形。我成功地创建了Vec<(String, String))>,但不是预期的Vec<(&str, &str)>
extern crate petgraph;
extern crate serde_json;

use petgraph::prelude::*;
use serde_json::{Value, Error};

fn main() {
    let data = r#"{
      "A": [ "B" ],
      "B": [ "C", "D" ],
      "D": [ "E", "F" ]
    }"#;
    let json_value: Value = serde_json::from_str(data).unwrap();
    let mut edges: Vec<(String, String)> = vec![];
    if let Value::Object(map) = json_value {
        for (from_edge, array) in &map {
            if let &Value::Array(ref array_value) = array {
                for edge in array_value {
                    if let &Value::String(ref to_edge) = edge {
                        edges.push((from_edge.clone(), to_edge.clone()))
                    }
                }
            }
        }
    }
    // let graph = DiGraphMap::<&str, ()>::from_edges(edges);
    //             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct
    //             `std::string::String`, found &str

}

我尝试了不同的方法:

  • 将图形类型更改为DiGraphMap ::<String,()>,但它不接受。
  • Vec<(String,String)>转换为Vec<(&str,&str)>。我阅读了this post,但没有帮助。
  • edges.push((&"a",&"b"))可以工作,但edges.push((&from.clone(),&to.clone()))不行。

这里可能有更好的提取边缘的方法。

1个回答

7
将图表类型更改为DiGraphMap :: <String,()>,但它不接受它。 GraphMap要求节点类型可复制。 String没有实现Copy
Vec<(String,String)>转换为Vec<(&str,&str)>
正如您链接的问题中所提到的,这是不可能的。您可以创建第二个Vec,其中包含引用原始String&str
let a: Vec<(String, String)> = vec![("a".into(), "b".into())];

let b: Vec<(&str, &str)> = a.iter()
    .map(|&(ref x, ref y)| (x.as_str(), y.as_str()))
    .collect();

然而,在这种情况下并不需要这样做。相反,将JSON数据读入模拟映射的数据结构中(我选择了BTreeMap),并保留String。然后,您可以构建一个对这些String的引用对的迭代器,从而构建图形:

extern crate petgraph;
extern crate serde_json;

use petgraph::prelude::*;
use std::collections::BTreeMap;
use std::iter;

fn main() {
    let data = r#"{
      "A": [ "B" ],
      "B": [ "C", "D" ],
      "D": [ "E", "F" ]
    }"#;

    let json_value: BTreeMap<String, Vec<String>> =
        serde_json::from_str(data).unwrap();

    let edges = json_value
        .iter()
        .flat_map(|(k, vs)| {
            let vs = vs.iter().map(|v| v.as_str());
            iter::repeat(k.as_str()).zip(vs)
        });

    let graph: DiGraphMap<_, ()> = edges.collect();
}

我需要把这个封装成一个函数。

这是可以做到的,虽然有些困难。由于JSON字符串包含UTF-8数据,Serde允许您获取对原始输入字符串的引用。您需要记住,您的图表(graph)不能超出输入(input)的生命周期:

fn main() {
    let data = r#"{
      "A": [ "B" ],
      "B": [ "C", "D" ],
      "D": [ "E", "F" ]
    }"#;

    let graph = example(data);
}

fn example(data: &str) -> serde_json::Result<DiGraphMap<&str, ()>> {
    let json_value: BTreeMap<&str, Vec<&str>> = serde_json::from_str(data)?;

    let edges = json_value
        .into_iter()
        .flat_map(|(k, vs)| iter::repeat(k).zip(vs));

    Ok(edges.collect())
}

不错!不过我需要将这个封装成一个函数:fn from_json(json_str: &str) -> Result<DiGraphMap<&str, ()>, Error>,但是我得到了 json_value 的生命周期不够长的错误。 - L. Meyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接