Search code examples
c#linqlistnested

Search in nested list


I have one List<List<Data>> with some List<Data> which is filled in a foreach-loop. So before I create a new List<Data>, I need to check, if some values already exist in any List<Data> in List<List<Data>>. If so, I need to return this list, to add the Data in this List<Data>.

    private List<List<DataToShow>> listList;
    private List<DataToShow> list;

    private void sortTestData()
    {
         listList = new List<List<DataToShow>>();

         foreach (DataToShow data in dataPack)
         {
             List<DataToShow> list = new List<DataToShow> { data };

                if (listList.Count != 0)
                    checkModusStatus(data);

                listList.Add(list);
            }
        }

        private void checkModusStatus(DataToShow data)
        {
            for (int i = 0; i < listList.Count; i++)
            {
                var value = listList[i].Where(x => (x.Mode == data.Mode) && (x.State == data.State));
            }        
}

So I always get null, although there are same entries

Any ideas beside two foreach Loops?


Solution

  • Check whether any list in a list of lists matches predicate

    Yes, you can check whether any list in your list of lists already contains an equivalent instance of the DataToShow you are thinking of adding like this:

    bool equivalentInstancePresent = listList.Any(dataList => dataList.Any(data => IsEquivalentInstance(data));
    
    private bool IsEquivalentInstance(DataToShow data)
    {
        // your check here
    }
    

    Using Any(predicate) will iterate over the respective IEnumerable and return true as soon as an element is found that matches the predicate. Otherwise it will return false after iteration is completed.

    A shorter version of the same linq expression:

    bool equivalentInstancePresent = listList.Any(dataList => dataList.Any(IsEquivalentInstance);
    

    Get first list in a list of list that matches predicate

    If you also need to return the list containing an equivalent instance – as stated in your question – you can use the following expression

    List<DataToShow> listWithEquivalentInstancePresent = listList.FirstOrDefault(dataList => dataList.Any(IsEquivalentInstance));
    

    As asked in the comments, you can also modify the predicate to limit witch items in each list to check. Note: I use a separate variable for the predicates in the following examples.

    Modify predicate to only check first x-th items

    If you want to limit your search scope to the first 5 items in each list:

    Func<IEnumerable<DataToShow>, bool> firstFiveItemsContainEquivalentInstance = (dataList) => dataList.Take(5).Any(IsEquivalentInstance);
    var listWhereFirstFiveItemsContainEquivalentInstance = listOfLists.FirstOrDefault(firstFiveItemsContainEquivalentInstance);
    

    Modify predicate to only check x-th item in each list

    Checking only the first item is relativly simple, as seen below.

    Func<IEnumerable<DataToShow>, bool> firstItemIsEquivalent = (dataList) => IsEquivalentInstance(dataList.FirstOrDefault());
    var listWhereFirstItemIsEquivalentInstance = listOfLists.FirstOrDefault(firstItemIsEquivalent);
    

    The predicate to check only the second item in each list looks as follows

    Func<IEnumerable<DataToShow>, bool> secondItemIsEquivalent = (dataList) => IsEquivalentInstance(dataList.Skip(1).Take(1).SingleOrDefault());