Linq选择嵌套列表的公共子集

时间:2013-08-28 13:11:58

标签: c# linq

我将从我的数据结构开始。

class Device
{
   public List<string> Interfaces { get; set; }
}

List<Device> allDevices;

我想使用Linq查询来选择allDevices列表中每个设备中存在的所有接口(字符串)。

谢谢你。

更新: 感谢Aron,我设法解决了这个问题。 这是我的解决方案:

List<string> commonInterfaces = allDevices.Select(device => device.Interfaces)
   .Cast<IEnumerable<string>>()
   .Aggregate(Enumerable.Intersect)
   .ToList();

3 个答案:

答案 0 :(得分:5)

您可以使用Enumerable.Intersect,例如:

IEnumerable<string> commonSubset = allDevices.First().Interfaces;
foreach (var interfaces in allDevices.Skip(1).Select(d => d.Interfaces))
{
    commonSubset = commonSubset.Intersect(interfaces);
    if (!commonSubset.Any())
        break;
}

DEMO

如果您想重复使用它,可以将其作为扩展方法:

public static IEnumerable<T> CommonSubset<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    return CommonSubset(sequences,  EqualityComparer<T>.Default);
}

public static IEnumerable<T> CommonSubset<T>(this IEnumerable<IEnumerable<T>> sequences, EqualityComparer<T> comparer)
{
    if (sequences == null) throw new ArgumentNullException("sequences");
    if (!sequences.Any()) throw new ArgumentException("Sequences must not be empty", "sequences");

    IEnumerable<T> commonSubset = sequences.First();
    foreach (var sequence in sequences.Skip(1))
    {
        commonSubset = commonSubset.Intersect(sequence, comparer);
        if (!commonSubset.Any())
            break;
    }
    return commonSubset;
}

现在使用非常简单(比较器可用于自定义类型):

var allInterfaces = allDevices.Select(d => d.Interfaces);
var commonInterfaces = allInterfaces.CommonSubset();
Console.Write(string.Join(",", commonInterfaces));

答案 1 :(得分:4)

var allInterfaces = from device in allDevices
                    from interface in device.Interfaces
                    select interface;

var allInterfaces = allDevices.SelectMany(device => device.Interfaces);

如果理查德道尔顿是正确的

var allCommonInterfaces = allDevices
              .Select(device => device.Interfaces.AsEnumerable())
              .Aggregate(Enumerable.Intersect);

为了好玩......这是一个更“优化”的解决方案。

public static IEnumerable<T> CommonSubset<T>
          (this IEnumerable<IEnumerable<T>> sequences, 
           EqualityComparer<T> comparer = null)
{
    if (sequences == null) throw new ArgumentNullException("sequences");


    Enumerator<T> enumerator = sequences.GetEnumerator();
    if(enumerator.GetNext() == false)
        throw new ArgumentException("Sequences must not be empty", "sequences");


    IEnumerable<T> first = enumerator.Current;
    HashSet<T> commonSubset = new HashSet<T>(first);
    while(enumerator.GetNext())
    {
        var nextSequence = enumerator.Current;
        var toRemove = commonSubset.Except(nextSequence, comparer ?? EqualityComparer<T>.Default).ToList();
        foreach(var r in toRemove)
            commonSubset.Remove(r);
    }
    return commonSubset;
}

答案 2 :(得分:2)

我猜你在找:

List<string> allInterfaces = allDevices.SelectMany(r=> r.Interfaces).ToList();

或者您可以选择IEnumerable<string>之类的:

var allInterfaces =  allDevices.SelectMany(r=> r.Interfaces);