[英]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.