C# 使用Linq查找包含一组对象的实例

C# 使用Linq查找包含一组对象的实例,c#,linq,C#,Linq,假设我有一套包。每个袋子里都有一套弹珠。我想选择包含特定大理石组合的袋子。在linq中最有效的方法是什么 代码: public enum Marble { Red, Green, Blue} public class Bag { public string Name; public List<Marble> contents; } var marbles = new[] { Marble.Red, Marble.Green }; var bags = new []

假设我有一套包。每个袋子里都有一套弹珠。我想选择包含特定大理石组合的袋子。在linq中最有效的方法是什么

代码:

public enum Marble { Red, Green, Blue}

public class Bag {
    public string Name;
    public List<Marble> contents;
}
var marbles = new[] { Marble.Red, Marble.Green };
 var bags = new [] 
            {new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
             new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
             new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}}
            };

//Output contains only bag Bar
var output = bags.Where(bag => bag.contents.All(x => marbles.Contains(x)) && 
                               marbles.All(x => bag.contents.Contains(x)));
public enum大理石{红、绿、蓝}
公厕袋{
公共字符串名称;
公开列表内容;
}
var marbles=new[]{Marble.Red,Marble.Green};
var行李=新[]
{new Bag{Name=“Foo”,contents=new List{Marble.Blue},
新包{Name=“Bar”,内容=新列表{Marble.Green,Marble.Red},
新包{Name=“Baz”,内容=新列表{Marble.Red,Marble.Green,Marble.Blue}
};
//输出仅包含bag Bar
var输出=袋子。其中(袋子=>袋子内容物。全部(x=>大理石。包含(x))&&
marbles.All(x=>bag.contents.Contains(x));

有更好的方法吗?

看来,您已经找到了一个很好的解决方案

尝试多种多样+重复的包!您的解决方案具有足够的可读性,并且涵盖了所需的业务逻辑

 var bags = new[] 
        {new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
         new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
         new Bag {Name = "Fiz", contents = new List<Marble> {Marble.Red, Marble.Green}},
         new Bag {Name = "REDS", contents = new List<Marble> {Marble.Red, Marble.Red}},
         new Bag {Name = "Biz", contents = new List<Marble> { Marble.Red } }, 
         new Bag {Name = "Griz", contents = new List<Marble> {Marble.Green, Marble.Green, Marble.Blue}},
         new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}}
        };

看来,您已经找到了一个很好的解决方案

尝试多种多样+重复的包!您的解决方案具有足够的可读性,并且涵盖了所需的业务逻辑

 var bags = new[] 
        {new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
         new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
         new Bag {Name = "Fiz", contents = new List<Marble> {Marble.Red, Marble.Green}},
         new Bag {Name = "REDS", contents = new List<Marble> {Marble.Red, Marble.Red}},
         new Bag {Name = "Biz", contents = new List<Marble> { Marble.Red } }, 
         new Bag {Name = "Griz", contents = new List<Marble> {Marble.Green, Marble.Green, Marble.Blue}},
         new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}}
        };
这里有一个替代解决方案。但对性能不确定

var output = bags.Where(bag => !bag.contents.Except(marbles).Any());

不完全正确

您可能想考虑将集合类型从List< /C> >改为<代码> HasSET> /COD>。这将允许您执行以下操作:

var output = bags.Where(bag => bag.contents.SetEqual(marbles));
这里有一个替代方案。但对性能不确定

var output = bags.Where(bag => !bag.contents.Except(marbles).Any());

不完全正确

您可能想考虑将集合类型从List< /C> >改为<代码> HasSET> /COD>。这将允许您执行以下操作:

var output = bags.Where(bag => bag.contents.SetEqual(marbles));

同意坎贝尔的回答。另一个建议是“为什么不使用
[Flags]
属性而不是
列表
”?可能会给你一些关于enum的想法同意campbell的回答。另一个建议是“为什么不使用
[Flags]
属性而不是
列表
”?可能会给您一些有关enum的想法如果您有许多行李并且希望获得最佳性能,您可以考虑使用:

public enum大理石{红、绿、蓝}
公共结构包
{
公共字符串名称;
公开列表内容;
}
班级计划
{
静态void Main(字符串[]参数)
{
var marbles=new[]{Marble.Red,Marble.Green};
var行李=新[]
{new Bag{Name=“Foo”,contents=new List{Marble.Blue},
新包{Name=“Bar”,内容=新列表{Marble.Green,Marble.Red},
新包{Name=“Baz”,内容=新列表{Marble.Red,Marble.Green,Marble.Blue}
};
//输出仅包含bag Bar
var output=bags.AsParallel()。其中(bag=>bag.contents.All(x=>marbles.Contains(x))&&
marbles.All(x=>bag.contents.Contains(x));
output.ForAll(bag=>Console.WriteLine(bag.Name));/“Bar”
}
}

如果您有许多行李,并且希望获得最佳性能,您可以考虑使用:

public enum大理石{红、绿、蓝}
公共结构包
{
公共字符串名称;
公开列表内容;
}
班级计划
{
静态void Main(字符串[]参数)
{
var marbles=new[]{Marble.Red,Marble.Green};
var行李=新[]
{new Bag{Name=“Foo”,contents=new List{Marble.Blue},
新包{Name=“Bar”,内容=新列表{Marble.Green,Marble.Red},
新包{Name=“Baz”,内容=新列表{Marble.Red,Marble.Green,Marble.Blue}
};
//输出仅包含bag Bar
var output=bags.AsParallel()。其中(bag=>bag.contents.All(x=>marbles.Contains(x))&&
marbles.All(x=>bag.contents.Contains(x));
output.ForAll(bag=>Console.WriteLine(bag.Name));/“Bar”
}
}

我认为set减法操作符是一种以更干净的方式完成它的方法。我已经给出了方法调用和linq表达式的实现方法

using System;
using System.Collections.Generic;
using System.Linq;

namespace Project
{
    public enum Marble { Red, Green, Blue}

    public class Bag {
        public string Name;
        public List<Marble> contents;
    }

    class Program
    {
        static void Main()
        {
            var marbles = new[] { Marble.Red, Marble.Green };
            var bags = new[] 
            {
                new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
                new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
                new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}},
                new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
                new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
                new Bag {Name = "Fiz", contents = new List<Marble> {Marble.Red, Marble.Green}},
                new Bag {Name = "REDS", contents = new List<Marble> {Marble.Red, Marble.Red}},
                new Bag {Name = "Biz", contents = new List<Marble> { Marble.Red } }, 
                new Bag {Name = "Griz", contents = new List<Marble> {Marble.Green, Marble.Green, Marble.Blue}},
                new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}}
            };

            // the method call version with set substraction operator
            var query_v2 = bags.Where(bag => bag.contents.Except(marbles).Count() == 0 &&
                                             marbles.Except(bag.contents).Count() == 0                                            
                                     );

            // print out the results 
            Console.WriteLine("query_v2...");
            foreach (var bag in query_v2)
            {
                Console.WriteLine(bag.Name);
            }
            Console.WriteLine();

            // Follwowing is a LINQ Expression version
            var linqversion = from bag in bags
                              let diff1 = bag.contents.Except(marbles).Count()
                              let diff2 = marbles.Except(bag.contents).Count()
                              where diff1 == 0 && diff2 == 0 // perfect match ?
                              select bag;

            Console.WriteLine("Linq expression version output...");
            foreach (var bag in linqversion)
            {
                Console.WriteLine(bag.Name);
            }
            Console.ReadLine();
        }
    }
}
    using System;
    using System.Collections.Generic;
    using System.Linq;


    namespace Project
    {
            public enum Marble { Red, Green, Blue}

            public class Bag {
                public string Name;
                public List<Marble> contents;
            }




    class Program
    {

        static void Main()
        {

            var marbles = new[] { Marble.Red, Marble.Green };
            var bags = new[] 
                    {new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
                     new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
                     new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}},
                     new Bag {Name = "Foo", contents = new List<Marble> {Marble.Blue}},
                     new Bag {Name = "Bar", contents = new List<Marble> {Marble.Green, Marble.Red}},
                     new Bag {Name = "Fiz", contents = new List<Marble> {Marble.Red, Marble.Green}},
                     new Bag {Name = "REDS", contents = new List<Marble> {Marble.Red, Marble.Red}},
                     new Bag {Name = "Biz", contents = new List<Marble> { Marble.Red } }, 
                     new Bag {Name = "Griz", contents = new List<Marble> {Marble.Green, Marble.Green, Marble.Blue}},
                     new Bag {Name = "Baz", contents = new List<Marble> {Marble.Red, Marble.Green, Marble.Blue}}
                    };





          // the method call version with set substraction   operator

           var  query_v2      = bags.Where(bag => bag.contents.Except(marbles).Count() == 0 &&
                                           marbles.Except(bag.contents).Count() == 0                                            
                                    );



               // print out the results 

               Console.WriteLine("query_v2...");

               foreach (var bag in query_v2)
               {
                   Console.WriteLine(bag.Name);
               }



           Console.WriteLine();








           // Follwowing is a LINQ Expression version
           //
           var linqversion = from bag in bags
                             let diff1 = bag.contents.Except(marbles).Count()
                             let diff2 = marbles.Except(bag.contents).Count()
                             where diff1 == 0 && diff2 == 0 // perfect match ?
                             select bag;


           Console.WriteLine("Linq expression version output...");

            foreach (var bag in linqversion)
            {
                Console.WriteLine(bag.Name);
            }


            Console.ReadLine();
        }









    }

}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间项目
{
公共枚举大理石{红、绿、蓝}
公厕袋{
公共字符串名称;
公开列表内容;
}
班级计划
{
静态void Main()
{
var marbles=new[]{Marble.Red,Marble.Green};
var行李=新[]
{
新包{Name=“Foo”,内容=新列表{Marble.Blue},
新包{Name=“Bar”,内容=新列表{Marble.Green,Marble.Red},
新包{Name=“Baz”,内容=新列表{Marble.Red,Marble.Green,Marble.Blue},
新包{Name=“Foo”,内容=新列表{Marble.Blue},
新包{Name=“Bar”,内容=新列表{Marble.Green,Marble.Red},
新包{Name=“Fiz”,内容=新列表{Marble.Red,Marble.Green},
新包{Name=“REDS”,内容=新列表{Marble.Red,Marble.Red},
新包{Name=“Biz”,内容=新列表{Marble.Red},
新包{Name=“Griz”,内容=新列表{Marble.Green,Marble.Green,Marble.Blue},
新包{Name=“Baz”,内容=新列表{Marble.Red,Marble.Green,Marble.Blue}
};
//使用set减法运算符的方法调用版本
var query_v2=bags.Where(bag=>bag.contents.Except(marbles).Count()==0&&
弹珠。除(袋子内容物)。计数()=0
);
//把结果打印出来
Console.WriteLine(“query_v2…”);
foreach(查询_v2中的var包)
{