我正在创建一个不可变的简单图类(它不需要支持循环或多个边)。每个节点由一个整数值表示,从0到numNodes。
此代码有效,但我认为Linq查询和for循环相当丑陋。你能想出一个更清晰的方法来填充_edges吗?
public class Graph {
private IList<IList<int>> _edges;
public int Nodes { get; private set;
}
public Graph(int numNodes, IList<Tuple<int,int>> edges) {
Nodes = numNodes;
_edges = new List<IList<int>>();
for(int i = 0; i < numNodes; i++) {
_edges.Add(new List<int>(
(from e in edges where e.Item1 == i
select e.Item2).Union(
(from e in edges where e.Item2 == i
select e.Item1).Distinct())));
}
}
public IEnumerable<int> Neighbors(int node) {
return _edges[node];
}
}
答案 0 :(得分:2)
这样的事情:
public class Graph2
{
private IList<HashSet<int>> _edges;
public int Nodes { get; private set; }
public Graph2(int numNodes, IList<Tuple<int, int>> edges)
{
Nodes = numNodes;
_edges = new List<HashSet<int>>(numNodes);
for (int i = 0; i < numNodes; i++)
{
_edges.Add(new HashSet<int>());
}
foreach (var edge in edges)
{
_edges[edge.Item1].Add(edge.Item2);
_edges[edge.Item2].Add(edge.Item1);
}
}
public IEnumerable<int> Neighbors(int node)
{
return _edges[node];
}
}
使用HashSet意味着您不必担心重复或具有复杂的Linq表达式。你也只能循环一次。
不幸的是,你仍然有初始的for循环来创建空的HashSets。
答案 1 :(得分:1)
public Graph(int numNodes, IList<Tuple<int, int>> edges)
{
Nodes = numNodes;
_edges = Enumerable.Range(0, numNodes).Select(num =>
edges.Where(x => x.Item1 == num).Select(x => x.Item2)
.Union(edges.Where(x => x.Item2 == num).Select(x => x.Item1))
.Distinct().ToList() as IList<int>
).ToList();
}
答案 2 :(得分:1)
以下是使用group by的替代方法:
public Graph(int numNodes, IList<Tuple<int, int>> edges) {
Nodes = numNodes;
_edges = new IList<int>[numNodes];
var groups = from e in edges
group e by e.Item1 into g
select new { Key = g.Key, Items = g.Select(s => s.Item2) };
foreach (var grp in groups) {
_edges[grp.Key] = grp.Items.ToList();
}
}
这将避免初始化边集合的初始for循环,但是当然在访问邻居时必须小心。
或许更漂亮的是:
public class Graph {
private IList<IEnumerable<int>> _edges;
public int Nodes { get; private set; }
public Graph(int numNodes, IList<Tuple<int, int>> edges) {
Nodes = numNodes;
_edges = new IList<int>[numNodes];
var groups = from e in edges
group e by e.Item1 into g select g;
foreach (var grp in groups) {
_edges[grp.Key] = (from g in grp select g.Item2).ToList();
}
}
public IEnumerable<int> Neighbors(int node) {
return _edges[node];
}
}