交叉这两个列表的最佳方法是什么?

时间:2013-02-16 18:24:43

标签: c# collections intersect

我在C#中有2个列表:

public class AvailableSlot
{
     public DateTime DateTime;
     public string Name
}

 List<AvailableSlot> list1 = GetList();
 List<AvailableSlot> list2 = GetAnotherList();

我想在这些列表上调用intersect,以找出同一日期两个列表中的项目。我知道我可以使用.Intersect来获取这些信息,但我的要求稍微复杂一些。我想返回一个相交的列表但我希望这个列表包含一个包含所有名称的对象列表。所以像这样:

  List<AvailableSlot2> intersectedList  . ..

其中的AvailableSlot2如下:

public class AvailableSlot2
{
     public DateTime DateTime;
     public string[] Names;
}

尝试在两个列表之间交叉后,是否有能力进行此转换?

3 个答案:

答案 0 :(得分:2)

我只需将两个列表合并,按DateTime分组,然后从组中提取名称:

var list1 = new List<AvailableSlot>
{
    new AvailableSlot { DateTime = new DateTime(2013, 2, 1), Name = "Alpha" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 2), Name = "Bravo" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 3), Name = "Charlie" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 1), Name = "Delta" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 2), Name = "Echo" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 3), Name = "Foxtrot" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 4), Name = "Golf" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 5), Name = "Hotel" }
};

var list2 = new List<AvailableSlot>
{
    new AvailableSlot { DateTime = new DateTime(2013, 2, 1), Name = "Apple" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 2), Name = "Bannana" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 1), Name = "Dog" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 2), Name = "Egg" },
    new AvailableSlot { DateTime = new DateTime(2013, 2, 5), Name = "Hi" }
};

var list3 = list1.Where (l => list2.Where (li => l.DateTime == li.DateTime).Any ())
   .Union(list2.Where (l => list1.Where (li => l.DateTime == li.DateTime).Any ()));

var groupedItems = from slot in list3
    group slot by slot.DateTime into grp
    select new AvailableSlot2 {
        DateTime = grp.Key,
        Names = grp.Select (g => g.Name).ToArray()
    };

foreach(var g in groupedItems)
{
    Console.WriteLine(g.DateTime);
    foreach(var name in g.Names)
        Console.WriteLine(name);
    Console.WriteLine("---------------------");
}

输出:

2/1/2013 12:00:00 AM
Alpha
Delta
Apple
Dog
---------------------
2/2/2013 12:00:00 AM
Bravo
Echo
Bannana
Egg
---------------------
2/5/2013 12:00:00 AM
Hotel
Hi
---------------------

答案 1 :(得分:0)

您可以使用LINQ to Objects Join()来排列具有相同DateTime属性的项目,然后将所有名称收集到一个数组中

var joinedItems = from slot1 in list1
                  join slot2 in list2
                  on slot1.DateTime equals slot2.DateTime into g
                  where g.Any()
                  select new AvailableSlot2
                  {
                      DateTime = slot1.DateTime,
                      Names = Enumerable.Range(slot1.Name,1).Union(g.Select(s => s.Name)).ToArray()
                  }

答案 2 :(得分:0)

您可以使用ToLookup

DateTime dt1 = new DateTime(2013, 2, 1);
DateTime dt2 = new DateTime(2013, 3, 1);
DateTime dt3 = new DateTime(2013, 4, 1);

var list1 = new List<AvailableSlot>
{
    new AvailableSlot{DateTime = dt1, Name = "n1",},
    new AvailableSlot{DateTime = dt2, Name = "n2",},
    new AvailableSlot{DateTime = dt1, Name = "n3",},
};

var list2 = new List<AvailableSlot>
{
    new AvailableSlot{DateTime = dt1, Name = "n1",},
    new AvailableSlot{DateTime = dt2, Name = "n2",},
    new AvailableSlot{DateTime = dt3, Name = "n3",},
};

var intersected = list1.Select (l => l.DateTime).
                        Intersect(list2.Select (l => l.DateTime));

var lookup = list1.Union(list2).ToLookup (
                                slot => slot.DateTime, slot => slot);

lookup.Where (l => intersected.Contains(l.Key)).Select (
    slot => new 
    {
        DateTime=slot.Key, 
        Names=slot.Select (s => s.Name)
    });

在这种情况下给出了结果:

DateTime            Names

01/02/2013 00:00    n1
                    n3
                    n1

01/03/2013 00:00    n2
                    n2

您当然可以使用Names = slot.Select(s =&gt; s.Name).Distinct()来获取不同的名称列表。