【问题标题】:LINQ, creating unique collection of a collectionLINQ,创建一个集合的唯一集合
【发布时间】:2012-03-27 17:18:54
【问题描述】:

我有

class Vertex{
    Graph _graph;
    float x;
    float y;
    string key;
    //and some similar atributes
    public IEnumerable<Edge> Edges{
        get{
            return _graph.Edges.Where(s => s.Source == this);
        }
    }
}
class Edge{
    Graph _graph;
    Vertex source;
    Vertex target;
}
class Graph
{
    private VertexCollection _vertexCollection; // extends List<Vertex>
    private EdgeCollection _edgeCollection; //extends List<Edge>
    public IEnumerable<Vertex> Vertexes
    {
        get
        {
            return _vertexCollection;
        }
    }
    public IEnumerable<Edge> Edges
    {
        get
        {
            return _edgeCollection;
        }
    }
    public IDictionary<Edge, bool> DrawableEdges
    {
        get
        {
            //want to return my uniq dictionary
        }
    }    

EdgesVertexes 被收集到列表中

一些例子:

A-->B // edge from vertex A to B
B-->C // edge from vertex B to C
C-->A // edge from vertex C to A
A-->C // edge from vertex A to C  -- this is two way edge

所以我想制作IDictionary&lt;Edge, bool&gt;,它将保持边缘(A-->B 和 B-->A 就像 1)和 bool - 如果它是两种方式或没有。

我需要它,因为当我现在绘制它们时,它会在彼此下方绘制 2 个箭头。我最好做 1 个箭头。

所以我被困在这里了......有人可以帮帮我吗?

【问题讨论】:

  • 请显示 Edge 和 Vertex 类的定义

标签: c# linq ienumerable


【解决方案1】:

我认为你应该为你的Edge 类实现IEquatable 接口:

public class Edge : IEquatable<Edge>
{
    ...

    public bool Equals(Edge other)
    {
        return (
            (other.Source == this.Source && other.Target == this.Target) ||
            (other.Target == this.Source && other.Source == this.Target));
    }

    public override int GetHashCode()
    {
        return (Source.GetHashCode() ^ Target.GetHashCode());
    }
}

并将您的边缘添加到HashSet&lt;Edge&gt; 集合中。然后你可以调用它的Contains方法来检查它是否包含边缘。

编辑:就像 Henk 所说,您还可以实现自定义 IEqualityComparer 类:

public sealed class EdgeComparer : IEqualityComparer<Edge>
{
    public static EdgeComparer Default { get; private set; }

    static EdgeComparer()
    {
        Default = new EdgeComparer();
    }

    private EdgeComparer()
    {
    }

    public bool Equals(Edge x, Edge y)
    {
        return (
            (x.Source == y.Source && x.Target == y.Target) ||
            (x.Target == y.Source && x.Source == y.Target));
    }

    public int GetHashCode(Edge edge)
    {
        return (edge.Source.GetHashCode() ^ edge.Target.GetHashCode());
    }
}

并使用

初始化您的哈希集
_drawableEdges = new HashSet<Edge>(EdgeComparer.Default);

【讨论】:

  • 或者编写一个单独的比较器来执行相同的逻辑。也提供了一种对称的方式来组合HashCodes
  • 您可能希望将== 替换为Equals 以避免NaN 问题。当然,OP 需要实现 Equals==!=GetHashCode()
  • @CodeInChaos 我认为在这种情况下== 足以检查相等性。
  • @BalazsTihanyi 不,不是。 NaN.Equals(NaN)==true` (NaN==NaN)==false
  • 但这会带来一些麻烦,因为我在这个图上使用了 Dijkstras 算法。从A到B你只能走一条路,如果我实现了这个,它也可以从B到A吗?不是吗?
【解决方案2】:

我假设您的 Edge 类有一个带有 2 个顶点的构造函数。可能的想法见下文(我没有编译这个,但希望你明白)。

foreach(Edge edge in Edges)
{
    Edge edge2 = new Edge(edge.V2, edge.V1);
    if (!dict.ContainsKey(edge) && !dict.ContainsKey(edge2))
    {
        dict[edge] = false; // first time we've seen this edge, so put it in dictionary
    }
    else if (!dict.ContainsKey(edge) && dict.ContainsKey(edge2))
    {
        dict[edge2] = true; // a bidirectional edge
    }
}

【讨论】:

  • 是的,我只需要想法
猜你喜欢
  • 2020-01-01
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多