mAx mAx - 1 month ago 11
C# Question

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

Answer

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