LINQ查询与Distinct和Union

时间:2011-03-11 17:23:13

标签: c# .net linq

我目前有2个查询返回MyModel列表,如下所示:

var q1 = ....
         select new MyModel()
         {
             TheData1 = ...
             TheData2 = ...
             TheUniqueID = ...
         }

var q2 = ....
         select new MyModel()
         {
             TheData1 = ...
             TheData2 = ...
             TheUniqueID = ...
         }

如果在q1我有:

TheUniqueID = 2,3,6,9,11 

在q2中我有:

TheUniqueID = 2,4,7,9,12

如何编写查询以便获取MyModel的列表

TheUniqueID = 2,3,4,6,7,9,11,12

换句话说,每个TheUniqueID只出现一次(即2和9不重复)。

我开始关注Union并且很明显,但我想知道我是否需要2个语句。

欢迎任何建议。

4 个答案:

答案 0 :(得分:23)

我认为frenchie需要一个MyModel列表,而不仅仅是TheUniqueID

您需要创建一个MyModelTheUniqueIDComparer类并将其新实例作为第二个参数传递给Union

class MyModelTheUniqueIDComparer : IEqualityComparer<MyModel>
{
    public bool Equals(MyModel x, MyModel y)
    {
        return x.TheUniqueID == y.TheUniqueID;
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.

    public int GetHashCode(MyModel myModel)
    {
        return myModel.TheUniqueID.GetHashCode();
    }
}

然后你可以打电话来得到结果:

var result = q1.Union(q2, new MyModelTheUniqueIDComparer());

有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/bb358407.aspx

<强>更新

试试这个:

public class A
{
    public string TheData1 { get; set; }
    public string TheData2 { get; set; }
    public string UniqueID { get; set; }
}

public class AComparer : IEqualityComparer<A>
{

    #region IEqualityComparer<A> Members

    public bool Equals(A x, A y)
    {
        return x.UniqueID == y.UniqueID;
    }

    public int GetHashCode(A obj)
    {
        return obj.UniqueID.GetHashCode();
    }

    #endregion
}

用这个测试:

var listOfA = new List<A>();
var q1 = from a in listOfA
                 select new A()
             {
                 TheData1 = "TestData",
                 TheData2 = "TestData",
                 UniqueID = a.UniqueID
             };

var anotherListOfA = new List<A>();
var q2 = from a in anotherListOfA
                 select new A()
                 {
                     TheData1 = "TestData",
                     TheData2 = "TestData",
                     UniqueID = a.UniqueID
                 };

q1.Union(q2, new AComparer());

确保您拥有using System.Linq;

答案 1 :(得分:7)

Union使用两个集合中的唯一值创建一个Enumerable。换句话说,您不需要Distinct

编辑:联盟here

的示例

edit2:忘了它不是你要连接的UniqueIDs列表。我删除了建议的代码,因为它错了。如果您实施IEqualityComparer,则应该可以执行简单的Union,但这可能会有点过分。

答案 2 :(得分:3)

如前所述,如果您将列表与.Union(组合在一起,则必须使用为您的类型传递IEqualityComparer的重载来定义唯一性。

var result = q1.Union(q2, myEqualityComparer);

否则,您可以更轻松地使用MoreLinq项目中的DistinctBy( x=> x.TheUniqueId)

var result = q1.Concat(q2).DistinctBy(c => c.TheUniqueID);

答案 3 :(得分:3)

没有IEqualityComparerer

的低效单行答案

使用MoreLinq源代码作为灵感,这将给出一个唯一的列表:

简短回答(OrderBy不是必要的,但如果没有使用,则答案为2,3,6,9,11,4,7,12):

var concattedUniqueList = theUniqueIDList1.Concat(theUniqueIDList2)
            .GroupBy(f=>f.UniqueID, f=>f).Select(g => g.First()).OrderBy(f=>f.UniqueID);

完整答案:

//INPUT
//theUniqueIDList1 = 2,3,6,9,11 
//theUniqueIDList2 = 2,4,7,9,12
//OUTPUT
//2,3,4,6,7,9,11,12
public class MyModel
{
    public string TheData1 { get; set; }
    public string TheData2 { get; set; }
    public int UniqueID { get; set; }
}

public static void GroupByEx1()
    {
        // Create a list of Models.
        List<MyModel> theUniqueIDList1 =
            new List<MyModel>{  new MyModel { TheData1="Barley",    UniqueID=2 },
                                    new MyModel { TheData1="Boots",     UniqueID=3 },
                                    new MyModel { TheData1="Whiskers",  UniqueID=6 },
                                    new MyModel { TheData1="Daisy",     UniqueID=9 },
                                    new MyModel { TheData1="Preti",     UniqueID=11 } };
        List<MyModel> theUniqueIDList2 =
            new List<MyModel>{  new MyModel { TheData1="Barley",    UniqueID=2 },
                                    new MyModel { TheData1="Henry",     UniqueID=4 },
                                    new MyModel { TheData1="Walsh",     UniqueID=7 },
                                    new MyModel { TheData1="Daisy",     UniqueID=9 },
                                    new MyModel { TheData1="Ugly",  UniqueID=12 } };

        var concattedUniqueList = theUniqueIDList1.Concat(theUniqueIDList2)
            .OrderBy(f=>f.UniqueID).GroupBy(f=>f.UniqueID, f=>f).Select(g => g.First());

        foreach (var item in concattedUniqueList)
        {
            Console.WriteLine("UniqueId: {0}({1})", item.UniqueID, item.TheData1);
        }
    }

void Main()
{
    GroupByEx1();               
    //2,3,4,6,7,9,11,12
}

注意:与使用IEqualityComparer进行速度相比 - 每次使用10000次 Concat为698 ns IEqualityComparer为100 ns

LinqPad

中开发