使用LINQ查询一系列列表

时间:2016-11-11 09:46:36

标签: c# linq foreach nested-lists

我正在使用名为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;
    }
}

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

所以,正如我在评论中已经说过的,构建递归函数应该可以解决问题。如果您是新手,可以在C#here中找到有关递归的一些基本信息。

该方法可能如下所示:

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);
}

之后,您可以在main方法中调用此方法,而不是循环:

    DeleteRecursively(0, CatTree, CatSchemeObject);

但是我也说过,请记住,在循环中调用方法对我来说似乎毫无意义,因为除了剩下的一条路径之外你已经清除了树,所以用同一棵树调用方法, category,将导致空树(在CatSchemeObject中)。

小心!我现在注意到另一件事:在您的Items属性上调用列表,然后删除条目, NOT 会影响您的源对象,因为ToList是生成一个新对象。它保留引用的原始对象,但删除仅影响列表。因此,您必须将结果列表写回Items属性,或者在Items对象中找到直接删除的方法。 (假设它是IEnumerable而不是具体的集合类型,你应该把它写回来。)

只需使用这个简单的示例尝试一下,您就会看到原始列表未被修改。

IEnumerable<int> test = new List<int>() { 1, 2, 3, 4 , 1 };

test.ToList().RemoveAll(a => a != 1);

答案 1 :(得分:0)

编辑:

所以这是另一种可能的方式来讨论下面的讨论。 不知道你真正需要什么,所以试试吧。

    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调用而导致数据丢失。它意味着“抓住第一件物品而不管一切”#39;。我知道你说你只有1个项目可以,但仍然......:)

如果这对您有用,请在评论中告诉我。

//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);
    }
}

答案 2 :(得分:0)

感谢任何想要帮助的人,但我自己以一种更容易的方式解决了这个问题。

我刚将完整的CategoryScheme对象发送到以XML格式转换它的方法,然后只有一行就可以了:

XmlDocument.Descendants("Category").Where(x => !CatList.Contains(x.Attribute("id").Value)).RemoveIfExists();