简体   繁体   中英

c# compare two lists based on sub items and return the difference

I need help in constructing a linq query to return missing sub items in the list.

I have a list of Items with classes as below

class Tags
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Items
{
    public string Name { get; set; }
    public List<Tags> TagList { get; set; }
}

Now I have 2 list OldItemList and NewItemList and I need to get all Items in OldItemList which have category(s) missing from NewItemList.

Eg. OldItemList AApple - tags => fruit, Organic BApple - tags => fruit, Organic

NewItemList AApple - tags => fruit, Fuji BApple - tags => fruit, Organic

The query should return me text => 'AApple missing tag Organic' .

I could get AApple out of the below query and i need help to get the missing tags

var missingItems = from oldItem in OldItemList
                   join newItem in NewItemList on oldItem.Name equals newItem.Name
                   where oldItem.TagList.Any(tagList1 => !newItem.TagList.Any(tagList2 => tagList1.Id == tagList2.Id))
                   select oldItem.Name;

whole code

class Tags
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Items
{
    public string Name { get; set; }
    public List<Tags> TagList { get; set; }
}
public class LinqTest
{
    public static void Test1()
    {
        List<Items> OldItemList = new List<Items>(){
        new Items
        {
            Name="A",
            TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=2, Name="2"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
        } ,
        new Items
        {
            Name="B",
            TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=2, Name="2"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
        } ,
        new Items
        {
            Name="C",
            TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=2, Name="2"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
        } ,
        new Items
        {
            Name="D",
            TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=2, Name="2"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
        }
       };


        List<Items> NewItemList = new List<Items>()
        {
            new Items
            {
                Name="A",
                TagList = new List<Tags>{ new Tags { Id = 12, Name = "1" }, new Tags{Id=2, Name="2"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
            } ,
            new Items
            {
                Name="B",
                TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=3, Name="3"}, new Tags{Id=4, Name="4"}}
            } ,
            new Items
            {
                Name="D",
                TagList = new List<Tags>{ new Tags{Id=1, Name="1"}, new Tags{Id=2, Name="2"}, new Tags{Id=4, Name="4"}}
            }
        };

        //To find missing items in variables
        var missingItems = from oldItem in OldItemList
                           join newItem in NewItemList on oldItem.Name equals newItem.Name
                           where oldItem.TagList.Any(tagList1 => !newItem.TagList.Any(tagList2 => tagList1.Id == tagList2.Id))
                           select oldItem.Name;

        foreach (string var in missingItems)
        {
            Console.WriteLine("var => " + var);
        }
    }

}

Answer from below comments

        var missingItems = from oldItem in OldItemList
                           join newItem in NewItemList on oldItem.Name equals newItem.Name
                           let missingTags = oldItem.TagList.Where
                            (oldTag => !newItem.TagList.Any(newTag => oldTag.Id == newTag.Id))
                           where missingTags.Any()
                           select new { Item = newItem.Name, MissingTags = missingTags.ToList() };

As I can understand the Issue , you can use this query-

  var missingItems = from oldItem in OldItemList
               join newItem in NewItemList on oldItem.Name equals newItem.Name
               where oldItem.TagList.Any(tagList1 => !newItem.TagList.Any(tagList2 => tagList1.Id == tagList2.Id))
               select new string{ oldItem.Name + " missing tag " + 
               String.Join(",",oldItem.TagList.Any(tagList1 => !newItem.TagList.Any(tagList2 => tagList1.Id == tagList2.Id)).Select(taglist=>taglist.Name))};

For now I am not using any IDE so if there is any typo just update me.

You can try to select all the missing tags for every new item in a let clause, if there is any missing tags you can select them and the item in an anonymous type:

var missingItems = from oldItem in OldItemList
                   join newItem in NewItemList on oldItem.Name equals newItem.Name
                   let missingTags = oldItem.TagList.Where(oldTag => !newItem.TagList.Any(newTag=> oldTag.Id == newTag.Id))
                   where missingTags.Any()
                   select new { Item = newItem, MissingTags = missingTags };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM