2010-09-25 59 views
1

可以說我有一套行李。每個包包含一組彈珠。我想選擇包含特定彈珠組合的包包。 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 [] 
      {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))); 

有沒有更好的辦法?

回答

0

我認爲設定減法運算符是一個沒有它,它應該在已經完成的方式一個更清潔的方式。我已經給出了方法調用和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(); 
     } 
    } 
} 
1

你已經有了一個很好的解決方案,它就會出現。

嘗試與許多不同+重複袋!您的解決方案足夠可讀,涵蓋了所需的業務邏輯。

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

+0

我一直在想這個問題。至於爲什麼第二個地方需要,這裏是一個反例。 '新包{名稱=「商務」,內容=新列表 {Marble.Red}}'。據我所知,他正在尋找等值。 – 2010-09-25 02:46:38

+0

@Jeff的確如此。我的解決方案也算不上2個紅軍。 :o – 2010-09-25 03:01:05

0

這裏有一個替代的解決方案。不確定性能。

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

不太正確。

您可能需要考慮將集合類型從List<Marble>更改爲HashSet<Marble>之類的東西。這將允許你這樣做:

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

同意坎貝爾的答案。另一個建議是「爲什麼不使用[Flags]屬性而不是List<MyEnum>」? This question可能會給你一些想法enum

0

如果你有很多行李,你想最大的性能,你可能看使用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" 
    } 
} 
0

我認爲集合減法運算符就是它應該以更簡潔的方式完成它的方式。我已經給出了方法調用和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(); 
     } 









    } 

} 
相關問題