使用LINQ查询列表的列表链
本文关键字:列表 查询 LINQ 使用 | 更新日期: 2023-09-27 18:17:21
我正在使用一个名为SDMX的XML标准。它相当复杂,但我将使它尽可能简短。我接收到一个叫做CategoryScheme
的物体。这个对象可以包含若干个Category
,每个Category
可以包含更多的Category
,以此类推,这个链可以是无限的。每个Category
都有一个唯一的ID。
通常每个Category
包含很多类别。与此对象一起,我正在接收一个数组,其中包含指示特定Category
嵌套位置的ID列表,然后我正在接收该类别的ID。我需要做的是创建一个对象来维护Category
对象的层次结构,但是每个Category
必须有,只有一个子,并且该子必须是导致特定Category
的树中的一个。所以我有一个想法,但为了做到这一点,我应该生成 LINQ查询在一个循环内,我不知道如何做到这一点。我想要尝试的更多信息在代码
让我们进入代码:
public void RemoveCategory(ArtefactIdentity ArtIdentity, string CategoryID, string CategoryTree)
{
try
{
WSModel wsModel = new WSModel();
// Prepare Art Identity and Array
ArtIdentity.Version = ArtIdentity.Version.Replace("_", ".");
var CatTree = JArray.Parse(CategoryTree).Reverse();
// Get Category Scheme
ISdmxObjects SdmxObj = wsModel.GetCategoryScheme(ArtIdentity, false, false);
ICategorySchemeMutableObject CatSchemeObj = SdmxObj.CategorySchemes.FirstOrDefault().MutableInstance;
foreach (var Cat in CatTree)
{
// The cycle should work like this.
// At every iteration it must delete all the elements except the correct one
// and on the next iteration it must delete all the elements of the previously selected element
// At the end, I need to have the CatSchemeObj full of the all chains of categories.
// Iteration 1...
//CatSchemeObj.Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Iteration 2...
//CatSchemeObj.Items.ToList().SingleOrDefault().Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Iteration 3...
//CatSchemeObj.Items.ToList().SingleOrDefault().Items.ToList().SingleOrDefault().Items.ToList().RemoveAll(x => x.Id != Cat.ToString());
// Etc...
}
}
catch (Exception ex)
{
throw ex;
}
}
谢谢你的帮助。
所以,正如我在评论中已经说过的,构建递归函数应该可以解决这个问题。如果你不熟悉它,你可以在这里找到一些关于c#递归的基本信息。
方法可以像这样:
private void DeleteRecursively(int currentRecursionLevel, string[] catTree, ICategorySchemeMutableObject catSchemeObj)
{
catSchemeObj.Items.ToList().RemoveAll(x => x.Id != catTree[currentRecursionLevel].ToString());
var leftoverObject = catSchemeObj.Items.ToList().SingleOrDefault();
if(leftoverObject != null) DeleteRecursively(++currentRecursionLevel, catTree, leftoverObject);
}
之后你可以在你的主方法中调用这个方法,而不是在循环中:
DeleteRecursively(0, CatTree, CatSchemeObject);
但正如我也说过的,请记住,在循环中调用方法,对我来说似乎毫无意义,因为你已经清除了树,除了一个剩余的路径,所以用相同的树调用方法,但另一个类别,将导致一个空树(在CatSchemeObject中)。
谨慎!另一件事要提我注意到现在:调用列表上的项目属性,然后删除条目,将不影响你的源对象,因为ToList正在生成一个新的对象。它保留了引用的原始对象,但删除只影响列表。因此,必须将结果列表写回Items属性,或者找到直接在Items对象中删除的方法。(假设它是一个IEnumerable而不是一个具体的集合类型,你应该把它写回去)。
用这个简单的例子试试,你会发现原来的列表没有被修改。
IEnumerable<int> test = new List<int>() { 1, 2, 3, 4 , 1 };
test.ToList().RemoveAll(a => a != 1);
编辑:
所以这是下面讨论之后的另一种可能的方式。不知道你真正需要的是什么,所以试试吧。
int counter = 0;
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
while(true)
{
var temp = list.Where(x => CatTree[counter++] == x.Id); // or != ? play with it .
list = temp.Items.ToList().SingleOrDefault();
if(list.Equals(default(list))
{
break;
}
}
}
我只是把你的问题翻译成2个解决方案,但我不确定你是否会因为SingleOrDefault调用而丢失数据。它的意思是"不顾一切地抓住第一件东西"。我知道你说你只有一件可以,但是……:)
请在评论中告诉我这是否适用于你。
//solution 1
// inside of this loop check each child list if empty or not
foreach (var Cat in CatTree)
{
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
while(true)
{
list.RemoveAll(x => x.Id != Cat.ToString());
list = list.ToList().SingleOrDefault();
if(list.Equals(default(list))
{
break;
}
}
}
}
//solution 2
foreach (var Cat in CatTree)
{
var list = CatSchemeObj.Items.ToList();
//check before you call it or you will get an error
if(!list.Equals(default(list)))
{
CleanTheCat(cat, list);
}
}
//use this recursive function outside of loop because it will cat itself
void CleanTheCat(string cat, List<typeof(ICategorySchemeMutableObject.Items) /*Place here whatever type you have*/> CatSchemeObj)
{
CatSchemeObj.RemoveAll(x => x.Id != cat);
var catObj = CatSchemeObj.Items.ToList().SingleOrDefault();
if (!catObj.Equals(default(catObj)){
CleanTheCat(cat, catObj);
}
}
感谢那些试图帮助我的人,但我自己用一种更容易的方法解决了这个问题。
我只是将完整的CategoryScheme对象发送给将其转换为XML格式的方法,然后只需要一行就可以了:
XmlDocument.Descendants("Category").Where(x => !CatList.Contains(x.Attribute("id").Value)).RemoveIfExists();