我有一个邻接列表是boost :: adjacency_list 其中GraphData是一个包含名称的结构
struct GraphData
{
std::string Divison;
std::vector<std::pair<std::string, int>> studentInfo;
// Student info contains Name and age
// Note I don't want to use anyother stucture inside GraphItem
}
如何使用动态属性读取和写入此学生信息?
void WriteGraph()
{
boost::dynamic_properties dp;
dp.property("Division", boost::get(&GraphItem::Division, graph));
boost::write_graphml(filename, graph, dp, true);
}
void ReadGraph()
{
boost::dynamic_properties dp;
std::ifstream file(fileName);
boost::read_graphml(file, graph, dp);
}
答案 0 :(得分:1)
回应the older question我有这个:
一些方法
不透明的成员对象
一种方法是像
student
一样对待Name
属性 属性:dp.property("Name", boost::get(&GraphData::Name, graph)); dp.property("Student", boost::get(&GraphData::student, graph));
所需要的就是告诉标准库如何流式传输
Student
个对象:inline static std::ostream& operator<<(std::ostream& os, Student const& s) { return os << s.roll_no << " " << std::quoted(s.division); } inline static std::istream& operator>>(std::istream& is, Student& s) { return is >> s.roll_no >> std::ws >> std::quoted(s.division); }
您将获得类似 Live On Wandbox 的XML。
<?xml version="1.0" encoding="UTF-8"?> <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
的xsi:的schemaLocation =&#34; HTTP://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd&#34;&GT; 玛丽 - 安妮·霍纳姆 80&#34;炼金术&#34; Mary-Anne Bufgloon 57&#34;戏剧&#34; 乔伊斯普雷特 8&#34;戏剧&#34; Philomena Joyce 3&#34;戏剧&#34; 詹姆斯塔辛克 78&#34;科学&#34;
单独属性
如果你真的想要单独的GraphML属性
roll_no
和division
,然后您返回transform_value_property_map
:void WriteGraph(std::ostream &os, Graph &graph) { boost::dynamic_properties dp; auto roll_no = [](Student const& s) { return s.roll_no; }; auto division = [](Student const& s) { return s.division; }; dp.property("Name", get(&GraphData::Name, graph)); dp.property("roll_no", boost::make_transform_value_property_map(roll_no,
get(&amp; GraphData :: student,graph))); dp.property(&#34; division&#34;,boost :: make_transform_value_property_map(division, get(&amp; GraphData :: student,graph)));
boost::write_graphml(os, graph, dp, true); }
请注意,出于阅读目的,需要LvaluePropertyMap,因此它是必需的 需要写得稍微宽松一点:
Graph ReadGraph(std::string const &fileName) { Graph graph; boost::dynamic_properties dp; auto roll_no = [](Student& s) ->auto& { return s.roll_no; }; auto division = [](Student& s) ->auto& { return s.division; }; dp.property("Name", get(&GraphData::Name, graph)); dp.property("roll_no", boost::make_transform_value_property_map(roll_no,
get(&amp; GraphData :: student,graph))); dp.property(&#34; division&#34;,boost :: make_transform_value_property_map(division, get(&amp; GraphData :: student,graph)));
std::ifstream file(fileName); boost::read_graphml(file, graph, dp); return graph; }
现在,您将获得类似 Live On Wandbox 的XML。
<?xml version="1.0" encoding="UTF-8"?> <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
的xsi:的schemaLocation =&#34; HTTP://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd&#34;&GT; Philomena Glinka 科学 3 Philomena Preet 炼金术 84 约翰哈巴库克 炼金术 19 欧内斯特·哈巴库克 哲学 31 John Bufgloon 科学 44
简化
你可以不用lambdas和它们之间做出区别 使用
进行写入/读取std::mem_fn
:static inline boost::dynamic_properties DynProps(Graph& g) { boost::dynamic_properties dp; dp.property("Name", get(&GraphData::Name, g)); auto student = get(&GraphData::student, g); dp.property("roll_no", make_transform_value_property_map(std::mem_fn(&Student::roll_no),
学生)); dp.property(&#34; division&#34;,make_transform_value_property_map(std :: mem_fn(&amp; Student :: division), 学生));
return dp; }
可用于
ReadGraph
和WriteGraph
的内容如下:Graph ReadGraph(std::string const &fileName) { Graph graph; auto dp = DynProps(graph); std::ifstream file(fileName); boost::read_graphml(file, graph, dp); return graph; } void WriteGraph(std::ostream &os, Graph &graph) { boost::write_graphml(os, graph, DynProps(graph), true); }
您仍然可以获得相同的XML。
完整列表
<强> Live On Wandbox 强>
#include <boost/graph/adjacency_list.hpp> #include <boost/property_map/transform_value_property_map.hpp> #include <boost/graph/graphml.hpp> struct Student { int roll_no; std::string division; }; struct GraphData { std::string Name; Student student; }; using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphData>; static inline boost::dynamic_properties DynProps(Graph& g) { boost::dynamic_properties dp; dp.property("Name", get(&GraphData::Name, g)); auto student = get(&GraphData::student, g); dp.property("roll_no", make_transform_value_property_map(std::mem_fn(&Student::roll_no),
学生)); dp.property(&#34; division&#34;,make_transform_value_property_map(std :: mem_fn(&amp; Student :: division), 学生));
return dp; } Graph ReadGraph(std::string const &fileName) { Graph graph; auto dp = DynProps(graph); std::ifstream file(fileName); boost::read_graphml(file, graph, dp); return graph; } void WriteGraph(std::ostream &os, Graph &graph) { boost::write_graphml(os, graph, DynProps(graph), true); } void WriteGraph(std::string const& fileName, Graph &graph) { std::ofstream ofs(fileName); WriteGraph(ofs, graph); } #include <boost/graph/graph_utility.hpp> namespace Gen { Graph graph(); } // generate random data int main() { { Graph g = Gen::graph(); WriteGraph("input.txt", g); } Graph g = ReadGraph("input.txt"); print_graph(g, get(&GraphData::Name, g)); // or as XML WriteGraph(std::cout << "==== XML version: ====\n\n", g); } /// generate data #include <boost/graph/random.hpp> #include <boost/random.hpp> #include <random> namespace Gen { namespace { namespace R = boost::random; R::mt19937 engine {42}; // { std::random_device{}() }; template <typename Range> auto sample(Range const &from) { return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1); } int roll() { return R::uniform_int_distribution<>(1, 100)(engine); } std::string division() { static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" }; return sample(d); } std::string name() { static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" }; static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" }; return sample(f) + " " + sample(l); } Student student() { return { roll(), division() }; } } Graph graph() { Graph g; boost::generate_random_graph(g, 5, 7, engine); for (auto vd: boost::make_iterator_range(vertices(g))) g[vd] = { name(), student() }; return g; } } // namespace Gen
您当前的问题会将vector
添加到混音中。这里有相关的帖子:read boost graph (boost::read_graphviz) where vertex contains vector
您可能会operator<<
/ operator>>
std::vector<T>
进入ADL陷阱。
如果上述内容尚未解决您遇到的问题,我今晚稍后会添加一个演示。
这比我希望的要复杂,因为在命名空间operator<<
内重载operator>>
/ ::std
只是品味不佳,所以我们需要一个包装类型:
using StudentInfo = std::vector<std::pair<std::string, int>>;
struct Wrapper {
StudentInfo& _si;
friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
for(auto& pair : sis._si)
os << std::quoted(pair.first) << pair.second << ';';
return os;
}
friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
StudentInfo::value_type pair;
while (is >> std::quoted(pair.first)) {
char ch;
if (is >> pair.second >> ch && ch == ';')
sis._si.push_back(pair);
else
return is;
}
if (!is.bad()) // eof this point is ok
is.clear();
return is;
}
};
注意,下面的代码会在名称和年龄之间添加
", "
。
现在,出现了一些额外的障碍,例如TransformValuePropertyMap不是LValuePropertyMap,除非返回的值是可变引用。
我选择做一个简单的CoercePropertyMap来&#34; wrap&#34;包装类型的属性:
template <typename T, typename Map> struct CoercePropertyMap : Map {
CoercePropertyMap(Map map) : Map(map){}
using value_type = T;
using reference = T;
};
template <typename T, typename Map>
CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
现在,我们可以把它们放在一起:
dp.property(&#34; studentInfo&#34;,coerce_map(get(&amp; GraphItem :: studentInfo,g)));
<强> Live On Wandbox 强>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
#include <iostream>
#include <iomanip>
using StudentInfo = std::vector<std::pair<std::string, int>>;
namespace /*static*/ {
struct Lit { char ch; };
static inline std::istream& operator>>(std::istream& is, Lit expected) {
char actual;
if (is >> actual && actual != expected.ch)
is.setstate(std::ios::failbit);
return is;
}
static StudentInfo null_info;
struct Wrapper {
StudentInfo& _si;
Wrapper(StudentInfo& si = null_info) : _si(si) {}
operator StudentInfo&() const { return _si; }
friend std::ostream& operator<<(std::ostream& os, const Wrapper sis) {
for(auto& pair : sis._si)
os << std::quoted(pair.first) << ", " << pair.second << ';';
return os;
}
friend std::istream& operator>>(std::istream& is, const Wrapper sis) {
StudentInfo::value_type pair;
while (is >> std::skipws >> std::quoted(pair.first)) {
if (is >> Lit{','} >> pair.second >> Lit{';'})
sis._si.push_back(pair);
else
return is; // error here is bad
}
if (!is.bad()) // just eof this point is ok
is.clear();
return is;
}
};
template <typename T, typename Map> struct CoercePropertyMap : Map {
CoercePropertyMap(Map map) : Map(map){}
using value_type = T;
using reference = T;
};
template <typename T, typename Map>
CoercePropertyMap<T, Map> coerce_map(Map map) { return map; }
}
struct GraphItem {
std::string Division;
StudentInfo studentInfo;
};
using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, GraphItem>;
static inline boost::dynamic_properties DynProps(Graph& g) {
boost::dynamic_properties dp;
dp.property("Division", get(&GraphItem::Division, g));
dp.property("studentInfo", coerce_map<Wrapper>(get(&GraphItem::studentInfo, g)));
return dp;
}
Graph ReadGraph(std::string const &fileName) {
Graph graph;
auto dp = DynProps(graph);
std::ifstream file(fileName);
boost::read_graphml(file, graph, dp);
return graph;
}
void WriteGraph(std::ostream &os, Graph &graph) {
boost::write_graphml(os, graph, DynProps(graph), true);
}
void WriteGraph(std::string const& fileName, Graph &graph) {
std::ofstream ofs(fileName);
WriteGraph(ofs, graph);
}
#include <boost/graph/graph_utility.hpp>
namespace Gen { Graph graph(); } // generate random data
int main() {
{
Graph g = Gen::graph();
WriteGraph("input.txt", g);
}
Graph g = ReadGraph("input.txt");
print_graph(g, get(&GraphItem::Division, g));
// or as XML
WriteGraph(std::cout << "==== XML version: ====\n\n", g);
}
/// generate data
#include <boost/graph/random.hpp>
#include <boost/random.hpp>
#include <random>
namespace Gen {
namespace {
namespace R = boost::random;
R::mt19937 engine {42}; // { std::random_device{}() };
template <typename Range> auto sample(Range const &from) {
return *std::next(boost::begin(from), R::uniform_int_distribution<>(1, boost::size(from))(engine) - 1);
}
int age() { return R::uniform_int_distribution<>(18, 27)(engine); }
std::string division() {
static std::string const d[] = { "science", "drama", "mathematics", "philosophy", "alchemy" };
return sample(d);
}
std::string name() {
static std::string const f[] = { "John", "Daisy", "Chuck", "Mary-Anne", "Ernest", "Philomena", "Joyce", "James" };
static std::string const l[] = { "Joyce", "Habakuk", "Hornam", "Bufgloon", "Glinka", "Tarsinck", "Preet" };
return sample(f) + " " + sample(l);
}
StudentInfo studentInfo() {
StudentInfo si;
auto const n = R::uniform_int_distribution<>(2,5)(engine);
for (int i = 0; i < n; ++i)
si.emplace_back(name(), age());
return si;
}
}
Graph graph() {
Graph g;
boost::generate_random_graph(g, 5, 7, engine);
for (auto vd: boost::make_iterator_range(vertices(g)))
g[vd] = { division(), studentInfo() };
return g;
}
} // namespace Gen
打印
philosophy --> drama
drama --> mathematics
drama --> philosophy
mathematics --> philosophy drama
drama --> philosophy drama
==== XML version: ====
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<key id="key0" for="node" attr.name="Division" attr.type="string" />
<key id="key1" for="node" attr.name="studentInfo" attr.type="string" />
<graph id="G" edgedefault="directed" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n0">
<data key="key0">philosophy</data>
<data key="key1">"James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;</data>
</node>
<node id="n1">
<data key="key0">drama</data>
<data key="key1">"James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;</data>
</node>
<node id="n2">
<data key="key0">drama</data>
<data key="key1">"James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;</data>
</node>
<node id="n3">
<data key="key0">mathematics</data>
<data key="key1">"James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;"John Bufgloon", 23;"Philomena Glinka", 26;"John Bufgloon", 19;"James Preet", 18;"Joyce Bufgloon", 27;</data>
</node>
<node id="n4">
<data key="key0">drama</data>
<data key="key1">"James Joyce", 18;"James Tarsinck", 25;"Daisy Joyce", 20;"Ernest Habakuk", 27;"Mary-Anne Joyce", 23;"Ernest Hornam", 18;"Daisy Hornam", 24;"James Hornam", 18;"Joyce Joyce", 22;"Mary-Anne Habakuk", 24;"John Bufgloon", 23;"Philomena Glinka", 26;"John Bufgloon", 19;"James Preet", 18;"Joyce Bufgloon", 27;"Daisy Joyce", 18;"Mary-Anne Habakuk", 24;"Ernest Joyce", 24;</data>
</node>
<edge id="e0" source="n0" target="n2">
</edge>
<edge id="e1" source="n1" target="n3">
</edge>
<edge id="e2" source="n2" target="n0">
</edge>
<edge id="e3" source="n3" target="n0">
</edge>
<edge id="e4" source="n3" target="n2">
</edge>
<edge id="e5" source="n4" target="n0">
</edge>
<edge id="e6" source="n4" target="n1">
</edge>
</graph>
</graphml>