代码之家  ›  专栏  ›  技术社区  ›  oillio

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

  •  1
  • oillio  · 技术社区  · 16 年前

    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)));
    

    有更好的办法吗?

    6 回复  |  直到 16 年前
        1
  •  0
  •   Jeff Mercado    16 年前

    我认为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();
            }
        }
    }
    
        2
  •  1
  •   p.campbell    16 年前

    看来你已经有了一个很好的解决方案。

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

     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}}
            };
    

    Where() .

    这将产生单个匹配项Bar。

     var output2 = bags.Where(b => b.contents.All(x => marbles.Contains(x))
                                && b.contents.Count == marbles.Count());
    

        3
  •  0
  •   Community Mohan Dere    9 年前

    同意坎贝尔的回答。另一个建议是“为什么不使用?” [Flags] List<MyEnum> "? This question enum .

        4
  •  0
  •   Nick Miller    16 年前

    如果你有很多包,你想要最好的性能,你可以考虑使用 PLinq

    public enum Marble { Red, Green, Blue }
    
    public struct Bag
    {
        public string Name;
        public List<Marble> contents;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
    
            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.AsParallel<Bag>().Where(bag => bag.contents.All(x => marbles.Contains(x)) &&
                                           marbles.All(x => bag.contents.Contains(x)));
    
            output.ForAll<Bag>(bag => Console.WriteLine(bag.Name));  // "Bar"
        }
    }
    
        5
  •  0
  •   Jeff Mercado    16 年前

    这里有另一个解决方案。但对表演不确定。

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

    不太对。

    您可能需要考虑将集合类型从 List<Marble> 像这样的 HashSet<Marble>

    var output = bags.Where(bag => bag.contents.SetEqual(marbles));
    
        6
  •  0
  •   explorer    16 年前

    我认为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();
            }
    
    
    
    
    
    
    
    
    
        }
    
    }