[英]c# linq filtering based on given list
我有这样的情况,我需要使用 C# Linq 并根据管理范围过滤标签,但遇到一个问题,我无法找到正确的方法,要么是 OR 运算符的问题,要么是我在 .All() 上做错了。
基本上我需要这样的东西:读取范围 - 必须匹配所有然后删除范围应该只匹配一个或多个,然后写入范围应该只匹配一个或多个
我对代码写了评论,也许有人有更好的想法如何过滤它?
这是示例:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp4
{
public class Admin
{
public List<string> ReadScopes { get; set; } = new List<string>();
public List<string> DeleteScopes { get; set; } = new List<string>();
public List<string> WriteScopes { get; set; } = new List<string>();
}
public class Tag
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public List<Rules> Rules { get; set; }
}
public class Rules
{
public string Value { get; set; }
public Scope Scope;
}
public enum Scope
{
Read, Delete, Write
}
class Program
{
static void Main(string[] args)
{
var tags = new List<Tag>
{
new Tag
{
Name = "Tag0",
// NO RULES AVAILABLE FOR ALL
Rules = new List<Rules>()
},
new Tag { Name = "Tag1", Rules = new List<Rules>()
{
//MUST MATCH ALL:
new Rules { Value = "Read_With_1Scope", Scope = Scope.Read },
new Rules { Value = "Read_With_2Scope", Scope = Scope.Read }
}},
new Tag { Name = "Tag2", Rules = new List<Rules>()
{
//MUST MATCH ALL:
new Rules { Value = "Read_With_1Scope", Scope = Scope.Read },
new Rules { Value = "Read_With_2Scope", Scope = Scope.Read },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Delete_With_1Scope", Scope = Scope.Delete },
new Rules { Value = "Delete_With_2Scope", Scope = Scope.Delete },
}},
new Tag { Name = "Tag3", Rules = new List<Rules>()
{
//MUST MATCH ALL:
new Rules { Value = "Read_With_1Scope", Scope = Scope.Read },
new Rules { Value = "Read_With_2Scope", Scope = Scope.Read },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Write_With_1Scope", Scope = Scope.Write },
new Rules { Value = "Write_With_2Scope", Scope = Scope.Write },
}},
new Tag { Name = "Tag4", Rules = new List<Rules>()
{
//MUST MATCH ALL:
new Rules { Value = "Read_With_1Scope", Scope = Scope.Read },
new Rules { Value = "Read_With_2Scope", Scope = Scope.Read },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Delete_With_1Scope", Scope = Scope.Delete },
new Rules { Value = "Delete_With_2Scope", Scope = Scope.Delete },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Write_With_1Scope", Scope = Scope.Write },
new Rules { Value = "Write_With_2Scope", Scope = Scope.Write },
}},
new Tag { Name = "Tag5", Rules = new List<Rules>()
{
// ONLY MUST MATCH ONE OF THESE:
new Rules { Value = "Delete_With_1Scope", Scope = Scope.Delete },
new Rules { Value = "Delete_With_2Scope", Scope = Scope.Delete },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Write_With_1Scope", Scope = Scope.Write },
new Rules { Value = "Write_With_2Scope", Scope = Scope.Write },
}},
new Tag { Name = "Tag6", Rules = new List<Rules>()
{
// ONLY MUST MATCH ONE OF THESE:
new Rules { Value = "Delete_With_1Scope", Scope = Scope.Delete },
new Rules { Value = "Delete_With_2Scope", Scope = Scope.Delete },
}},
new Tag { Name = "Tag7", Rules = new List<Rules>()
{
// ONLY MUST MATCH ONE OF THESE:
new Rules { Value = "Write_With_1Scope", Scope = Scope.Write },
new Rules { Value = "Write_With_2Scope", Scope = Scope.Write },
}},
};
//GET Tag0, Tag1
var admin = new Admin
{
ReadScopes = new List<string> { "Read_With_1Scope", "Read_With_2Scope" },
};
//GET Tag0, Tag1, Tag2
var admin1 = new Admin
{
ReadScopes = new List<string> { "Read_With_1Scope", "Read_With_2Scope" },
DeleteScopes = new List<string> { "Delete_With_1Scope" },
};
//.....
//.....
//GET Tag0, Tag7
var admin2 = new Admin
{
WriteScopes = new List<string> { "Write_With_1Scope" },
};
//ADMIN1 TEST - PROBLEM WITH TAG2
var available_tags = tags
.Where(tag => tag.Rules.All(rule =>
admin1.ReadScopes.Any(value => rule.Value == value)
||
admin1.DeleteScopes.Any(value => rule.Value == value)
||
admin1.WriteScopes.Any(value => rule.Value == value)
));
foreach (var available_tag in available_tags)
{
Console.WriteLine(available_tag.Name);
}
Console.ReadLine();
}
}
}
如果我误解了,请原谅我,但让我们看看。 你说 admin1,应该收到这个标签:
new Tag { Name = "Tag2", Rules = new List<Rules>()
{
//MUST MATCH ALL:
new Rules { Value = "Read_With_1Scope", Scope = Scope.Read },
new Rules { Value = "Read_With_2Scope", Scope = Scope.Read },
// AND THEN MUST MATCH ONE OF THESE:
new Rules { Value = "Delete_With_1Scope", Scope = Scope.Delete },
new Rules { Value = "Delete_With_2Scope", Scope = Scope.Delete },
}},
所以为了让 admin1 收到这个标签,他必须满足所有条件才能收到这个标签。 但是,他缺少 Delete_with_2Scope,因此由于他不满足该条件,因此他没有收到标签。
例如,如果您在他的删除范围中添加该范围,那么他应该收到 tag2。
您的原始代码遍历所有标签并过滤以仅采用满足该标签中所有规则条件的标签( tag.Rules.All(...)
),显然不是您想要的
要修复它,您需要按每个标签的范围过滤规则,如果您希望所有过滤的规则都匹配,则使用All()
,如果其中任何一个匹配,则使用Any()
。 像这样的东西:
var available_tags = tags
.Where(tag =>
tag.Rules.Where(r => r.Scope == Scope.Read).All(r => admin1.ReadScopes.Contains(r.Value))) &&
(tag.Rules.Where(r => r.Scope == Scope.Write).Count() == 0 || tag.Rules.Where(r => r.Scope == Scope.Write).Any(r => admin1.WriteScopes.Contains(r.Value))) &&
(tag.Rules.Where(r => r.Scope == Scope.Delete).Count() == 0 || tag.Rules.Where(r => r.Scope == Scope.Delete).Any(r => admin1.DeleteScopes.Contains(r.Value))));
检查Count() == 0
是必要的,因为如果该范围没有规则,则Any()
将返回 false。
为了使它更好更高效,我将创建一些辅助方法,例如:
private static bool MatchAllRules(List<string> adminRules, List<Rules> allRules, Scope scope)
{
var rulesByScope = allRules.Where(r => r.Scope == scope).ToList();
return rulesByScope.All(r => adminRules.Contains(r.Value));
}
private static bool MatchAnyRule(List<string> adminRules, List<Rules> allRules, Scope scope)
{
var rulesByScope = allRules.Where(r => r.Scope == scope).ToList();
if (rulesByScope.Count == 0)
{
return true;
}
return rulesByScope.Any(r => adminRules.Contains(r.Value));
}
并像这样使用它们:
var available_tags = tags
.Where(tag =>
MatchAllRules(admin1.ReadScopes, tag.Rules, Scope.Read) &&
MatchAnyRule(admin1.WriteScopes, tag.Rules, Scope.Write) &&
MatchAnyRule(admin1.DeleteScopes, tag.Rules, Scope.Delete));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.