C# 使用LINQ筛选列表

C# 使用LINQ筛选列表,c#,linq,collections,tags,ienumerable,C#,Linq,Collections,Tags,Ienumerable,我有一个项目对象列表: IEnumerable<Project> projects 我想筛选我的列表(项目),以仅返回在筛选器中列出了所有标记的项目(在本例中,至少是标记属性中的标记1和标记3) 我试图使用,其中()和包含(),但这似乎只有在与单个值进行比较时才起作用。我如何将一个列表与另一个列表进行比较,其中我需要对筛选列表中的所有项目进行匹配???编辑:更好的做法是这样做: var result = projects.Where(p => filtedTags.All(t

我有一个项目对象列表:

IEnumerable<Project> projects
我想筛选我的列表(项目),以仅返回在筛选器中列出了所有标记的项目(在本例中,至少是标记属性中的标记1和标记3)


我试图使用,其中()和包含(),但这似乎只有在与单个值进行比较时才起作用。我如何将一个列表与另一个列表进行比较,其中我需要对筛选列表中的所有项目进行匹配???

编辑:更好的做法是这样做:

var result = projects.Where(p => filtedTags.All(t => p.Tags.Contains(t)));
var filteredProjects = 
    projects.Where(p => filteredTags.All(tag => p.Tags.Contains(tag)));
EDIT2:老实说,我不知道哪一个更好,所以如果性能不重要,就选择你认为更可读的。如果是的话,你将不得不以某种方式对其进行基准测试


可能
Intersect
是一种方法:

void Main()
{
    var projects = new List<Project>();
    projects.Add(new Project { Name = "Project1", Tags = new int[] { 2, 5, 3, 1 } });
    projects.Add(new Project { Name = "Project2", Tags = new int[] { 1, 4, 7 } });
    projects.Add(new Project { Name = "Project3", Tags = new int[] { 1, 7, 12, 3 } });

    var filteredTags = new int []{ 1, 3 };
    var filteredProjects = projects.Where(p => p.Tags.Intersect(filteredTags).Count() == filteredTags.Length);  
}


class Project {
    public string Name;
    public int[] Tags;
}
void Main()
{
var projects=新列表();
添加(新项目{Name=“Project1”,Tags=newint[]{2,5,3,1});
添加(新项目{Name=“Project2”,Tags=newint[]{1,4,7});
添加(新项目{Name=“Project3”,Tags=newint[]{1,7,12,3});
var filteredTags=newint[]{1,3};
var filteredProjects=projects.Where(p=>p.Tags.Intersect(filteredTags.Count()==filteredTags.Length);
}
班级项目{
公共字符串名称;
公共int[]标签;
}
虽然一开始看起来有点难看。如果您不确定列表中的所有标记是否唯一,则可以首先将
Distinct
应用于
filteredTags
,否则计数比较将无法按预期进行

var filtered = projects;
foreach (var tag in filteredTags) {
  filtered = filtered.Where(p => p.Tags.Contains(tag))
}

这种方法的好处是,您可以增量地优化搜索结果。

我们应该有包含(至少)所有过滤标记的项目,或者用另一种方式说,排除不包含所有过滤标记的项目。 因此,我们可以使用Linq
之外的方法来获取那些未包含的标记。然后,我们可以使用
Count()==0
仅包含不排除任何标记的标记:

var res = projects.Where(p => filteredTags.Except(p.Tags).Count() == 0);
或者我们可以通过将
Count()==0
替换为
,使其稍微快一点!Any()

基于

EqualAll是最能满足您需求的方法

public void Linq96() 
{ 
    var wordsA = new string[] { "cherry", "apple", "blueberry" }; 
    var wordsB = new string[] { "cherry", "apple", "blueberry" }; 

    bool match = wordsA.SequenceEqual(wordsB); 

    Console.WriteLine("The sequences match: {0}", match); 
} 

为什么?它将不允许项目与标签“1,2,3”或我遗漏了什么?我不确定所有是正确的,因为它需要工作,如果它至少有1和3,但它可以有更多。All()不是要根据1和3验证列表中的每一项吗?我们可以稍微修改上面的代码以获得所需的结果。var result=projects.Where(p=>filtedTags.All(t=>p.Tags.Contains(t))@ooo@nyinyithann:对不起,我的英语很差,所以我误解了OP的问题。我认为你的
Intersect
方式比你的“还更好”更清晰method@AakashM:我真的不知道,我现在正在努力决定。我不喜欢
Count()
因为它必须评估标签
IEnumerable
,但我自己也很困惑-1我认为你的答案是错误的和令人困惑的(因为假设人们会去链接阅读样本,并理解EqualAll是他们在页面中给出的用于采样SequenceEqual方法的名称).和SequenceEqual在这种情况下不起作用,因为“项目”的标记数可能比过滤的标记数多,因此仍应被视为成功匹配。这种方法的缺点是会多次循环所有项目(与过滤的标记数相同)。虽然上述方法只循环一次项目。虽然在大多数情况下,它们的性能相同,但在一些常见情况下(想想使用IEnumerable with yield或IQueryable的项目),它们的性能会明显更好。
var res = projects.Where(p => !filteredTags.Except(p.Tags).Any());
public void Linq96() 
{ 
    var wordsA = new string[] { "cherry", "apple", "blueberry" }; 
    var wordsB = new string[] { "cherry", "apple", "blueberry" }; 

    bool match = wordsA.SequenceEqual(wordsB); 

    Console.WriteLine("The sequences match: {0}", match); 
}