我有一个对象集合,其中每个对象包含另一个对象集合。我需要找到最快的方法来检查它是否包含List<string>
的所有值。
下面是一个例子:
class Video {
List<Tag> Tags;
}
class Tag{
public Tag (string name){
Name = name;
}
string Name;
}
List<string> selectedTags = new List<string>();
selectedTags.Add("Foo");
selectedTags.Add("Moo");
selectedTags.Add("Boo");
List<Video> videos = new List<Video>();
// Case A
Video videoA = new Video();
videoA.Tags = new List<Tag>();
videoA.Tags.Add(new Tag("Foo"));
videoA.Tags.Add(new Tag("Moo"));
videos.Add(videoA);
videoA
不应该被LINQ选中,因为它不包含所有的标签。
// Case B
Video videoB = new Video();
videoB.Tags = new List<Tag>();
videoB.Tags.Add(new Tag("Foo"));
videoB.Tags.Add(new Tag("Moo"));
videoB.Tags.Add(new Tag("Boo"));
videos.Add(videoB);
videoB
应该被LINQ选中,因为它包含了所有的标签。
我尝试了foreach
循环,但它太慢了,所以我正在寻找LINQ解决方案。
foreach (Video video in videos) {
if (video.Tags.Count() > 0) {
bool containAllTags = true;
foreach (string tagToFind in selectedTags) {
bool tagFound = false;
foreach (Tag tagItem in video.Tags) {
if (tagToFind == tagItem.Name)
tagFound = true;
}
if (!tagFound)
containAllTags = false;
}
if (containAllTags)
result.Add(videoItem);
}
}
结果LINQ应该是这样的:
IEnumerable<Video> = from vid in videos
where vid.Tags.( ..I dont know.. )
select vid;
我尝试了几种.Any
, .All
等方法。但是我找不到解决方案,我不能使用.Intersect
,因为一个是字符串的List
,另一个是对象的List
。注意,在生产版本中,Video
和Tag
元素有更多的属性。
对于当前的代码,逻辑上需要:
IEnumerable<Video> result = from vid in videos
where selectedTags.All(tag =>
vid.Tags.Any(t => t.Name == tag))
select vid;
或等价:
var result = videos.Where(vid => selectedTags.All(tag =>
vid.Tags.Any(t => t.Name == tag)));
这是假设您已经将Tag.Name
和Video.Tags
设置为公共的,当然—理想情况下是作为属性而不是作为字段。
请注意我们如何调用All
对selectedTags
,因为(假设我已经正确阅读了您的要求)所有选定的标签都存在于视频中是很重要的-所有视频的标签都被选中是而不是重要的。
如果你有很多标签要检查,并且每个视频有很多标签,那么这可能会相对较慢。
然而,知道如何优化它实际上取决于其他一些选择:
- 如果标签的顺序不重要,你能改变
Video.Tags
是一个集合而不是一个列表吗? - 您是否总是浏览同一组视频,以便您可以执行一些预处理?
- 可用的标签总数大吗?那么每个视频的标签数量呢?所选标签的数量如何?
或者,您可以将每个视频投影到它的"标签列表"中,并检查所选集合中是否有任何不在视频集合中的标签:
var result = videos.Where(vid => !selectedTags.Except(vid.Tags.Select(t => t.Name))
.Any());