让我们说我有一套袋子。每个包包含一套大理石。我想选择包含特定大理石组合的袋子。在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 :(得分: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());
击> <击> 撞击>
答案 1 :(得分:0)
这是另一种解决方案。虽然不确定性能。
var output = bags.Where(bag => !bag.contents.Except(marbles).Any());
不太对。
您可能需要考虑将集合类型从List<Marble>
更改为HashSet<Marble>
之类的内容。这将允许您这样做:
var output = bags.Where(bag => bag.contents.SetEqual(marbles));
答案 2 :(得分:0)
同意坎贝尔的回答。另一个建议是“为什么不使用[Flags]
属性而不是List<MyEnum>
”? This question可能会就enum
提供一些想法。
答案 3 :(得分: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"
}
}
答案 4 :(得分:0)
我认为set subraction运算符就是以更清晰的方式完成它的方式。我已经给出了方法调用和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();
}
}
}
答案 5 :(得分:0)
我认为set subraction运算符就是以更清晰的方式完成它的方式。我已经给出了方法调用和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();
}
}
}