How to change the following foreach code to Linq Query? - c#

public class A
{
public List<Data> data { get; set; }
}
public class Data
{
public int ID { get; set; }
public int values { get; set; }
}
public class B
{
public List<DifferentData> Data { get; set; }
}
public class DifferentData
{
public int NewID { get; set; }
public int Differentvalues { get; set; }
public string AdditionalInfo { get; set; }
}
I have a code like below
var TopAClassData = new A();
var TopBClassData = new B();
var anotherItemD = new DifferentData();
foreach (var item in TopAClassData.data)
{
foreach (var anotherItem in TopBClassData.Data)
{
if (item.ID == anotherItem.NewID)
{
item.values = anotherItemD.Differentvalues;
}
}
}
I'm trying to set the Differentvalues from the List to values field of List if the NewId and ID are matching. Is there anyway to convert the foreach code to simpler linq query

You can join two lists and then enumerate:
var items = TopAClassData.data
.Join(TopBClassData.Data, x => x.ID, x => x.NewId,
(item, anotherItem) => item);
foreach(var item in items)
{
item.values = anotherItemD.Differentvalues;
}

Here's a fairly nice LINQ version:
IEnumerable<Data> items =
from item in TopAClassData.data
join anotherItem in TopBClassData.Data on item.ID equals anotherItem.NewID
select item;
foreach (Data item in items)
item.values = anotherItemD.Differentvalues;

Related

Dynamic LINQ Query System.Linq.Dynamic.Core

System.Linq.Dynamic.Core.Exceptions.ParseException: 'No property or field 'Name' exists in type 'IEnumerable`1''
How to use Complex object to do order by in Dynamic linq query! I am using System.Linq.Dynamic.Core for dynamic linq query.
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Student> Students { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Course Course { get; set; }
}
using (var context = new SchoolContext())
{
var list = context.Courses.Include("Students").AsQueryable();
var result = list.OrderBy("Students.Name").ToList();
foreach (var item in list)
{
Console.WriteLine("Hello World!" + item.Name );
}
}
The issue you are running into is trying to run an order by on a list.
If you want the students ordered by name in a course try the following
var list = context.Courses.Include(c => c.Students).AsQueryable();
var result = list.Select(course =>
new Course {
Id = course.Id,
Name = course.Name,
Students = course.Students.OrderBy(s => s.Name)
}).ToList();
foreach (var item in list)
{
foreach(var student in item.Students)
{
Console.WriteLine("Hello World!" + student.Name );
}
}

using linq and c# to create a nested list object from a flat list object

I have a question. It's about linq in combination with c#.
I want to create a tree structure from a flatten structure in a pre defined object structure.
The following code which I've got work, but both are not exactly what i want.
In linq:
var result = listAgenderingen.GroupBy(records => records.Agnnummer)
.Select(group => new { AgnNummer = group.Key, Items = group.ToList()}).ToList();
the issue is that this does not result in the object I want.
So I've rewritten this to the following code
List<string> test = listAgenderingen.Select(x => x.Agnnummer).Distinct().ToList();
foreach (var item in test)
{
List<Agendering> listAgendering = listAgenderingen.Where(agend => agend.Agnnummer == item).OrderBy(ord => ord.Agnnummer).ToList();
AgnAgendering AgnAgendering = new AgnAgendering() {AgnNummer =item, Agenderingen = listAgendering };
}
this code actually works correct. but for 200000 records, it's taking a lot of time while the original linq takes a few seconds.
my question is can the linq be rewritten so it will create or convert to the richt object?
the structure of the classes:
public class Agendering
{
public int AgnID { get; set; }
public string Agnnummer { get; set; }
}
public class AgnAgendering
{
public string AgnNummer { get; set; }
public List<Agendering> Agenderingen { get; set; }
}
I hope someone has a sollution.
If I understand correctly, you want:
var result = listAgenderingen.GroupBy(records => records.Agnnummer)
.Select(group => new AgnAgendering { AgnNummer = group.Key, Agenderingen = group.ToList()}).ToList();
Your properties naming makes it absolutely unreadable and unclear.
Assuming that you have a flat structure like:
public class Item
{
public int ID { get; set; }
public int? ParentID { get; set; }
}
and you want a tree-like structure:
public class TreeItem
{
public int ID { get; set; }
public TreeItem Parent { get; set; }
public List<TreeItem> Children { get; set; }
public TreeItem(int id)
{
ID = id;
Children = new List<TreeItem>();
}
public TreeItem(int id, TreeItem parent) : this(id)
{
Parent = parent;
}
}
You can do most optimally in O(n) using Dictionary:
Item[] items = ...;
Dictionary<int, TreeItem> result = new Dictionary<int, TreeItem>();
foreach (var item in items.OrderBy(x => x.ParentID ?? -1))
{
TreeItem current;
if (item.ParentID.HasValue)
{
TreeItem parent = result[item.ParentID]; // guaranteed to exist due to order
current = new TreeItem(item.ID, parent);
parent.Children.Add(current);
} else {
current = new TreeItem(item.ID);
}
}
TreeItem[] treeItems = result.Values.ToArray();

Sorting and Updating a Generic List of Object based on a Sub Object

I have the following objects:
public class TestResult
{
public string SectionName { get; set; }
public int Score { get; set; }
public int MaxSectionScore { get; set; }
public bool IsPartialScore { get; set; }
public string Name { get; set; }
public int NumberOfAttempts { get; set; }
}
public class TestResultGroup
{
public TestResultGroup()
{
Results = new List<TestResult>();
Sections = new List<string>();
}
public List<TestResult> Results { get; set; }
public List<string> Sections { get; set; }
public string Name { get; set; }
public int Rank { get; set; }
}
So, a TestResultGroup can have any number of results of type TestResult. These test results only differ by their SectionName.
I have a List<TestResultGroup> which I need to sort into descending order based on a score in the Results property, but only when Results has an item whos SectionName = "MeanScore" (if it doesnt have this section we can assume a score of -1). How would I go about ordering the list? Ideally I would also like to apply the result of this ordering to the Rank property.
Many Thanks
List<TestResultGroup> groups = ...
// group test result groups by the same score and sort
var sameScoreGroups = groups.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(gr => gr.Key);
int rank = 1;
foreach (var sameScoreGroup in sameScoreGroups)
{
foreach (var group in sameScoreGroup)
{
group.Rank = rank;
}
rank++;
}
// to obtain sorted groups:
var sortedGroups = groups.OrderByDescending(gr => gr.Rank).ToArray();
Or even write one expression with a side effect:
List<TestResultGroup> groups = ...
int rank = 1;
var sortedGroups = groups
.GroupBy(
gr =>
{
var meanResult = gr.Results.FirstOrDefault(res => res.SectionName == "MeanScore");
return meanResult != null ? meanResult.Score : -1;
})
.OrderByDescending(grouping => grouping.Key)
.SelectMany(grouping =>
{
int groupRank = rank++;
foreach (var group in grouping)
{
group.Rank = groupRank;
}
return grouping;
})
.ToArray(); // or ToList

Convert list of items to list of tree nodes that have children

I have the following class
public class Item
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Text { get; set; }
}
And the following class for tree view
public class TreeViewModel
{
public TreeViewModel()
{
this.Children = new List<TreeViewModel>();
}
public int Id { get; set; }
public int NodeId { get; set; }
public string Text { get; set; }
public bool Expanded { get; set; }
public bool Checked { get; set; }
public bool HasChildren
{
get { return Children.Any(); }
}
public IList<TreeViewModel> Children { get; private set; }
}
I will receive list of items and I would to convert it to tree.
the item that not have parent id it will the main node.
example: if i have the following items
item[0] = Id:0 Text:User ParentId:3
item[1] = Id:1 Text:Role ParentId:3
item[2] = Id:2 Text:SubUser ParentId:0
item[3] = Id:3 Text:Admin ParentId:null
item[4] = Id:4 Text:SuperAdmin ParentId:null
item[5] = Id:5 Text:Doha ParentId:4
the following item it will list of tree
I tried to make recursive function to do that , but i have no result
You don't need a recursive function to do this:
var models = items.Select(i => new TreeViewModel
{
Id = i.Id,
...
}).ToList();
foreach (var model in models){
model.Children.AddRange(models.Where(m => m.ParentId == model.Id));
}
If you then want to get the roots of your tree, you can use:
var roots = models.Where(m => !m.ParentId.HasValue);
Here is a fast O(N) time complexity method of doing that:
List<Item> list = ...;
// Pre create all nodes and build map by Id for fast lookup
var nodeById = list
.Select(item => new TreeViewModel { Id = item.Id, Text = item.Text })
.ToDictionary(item => item.Id);
// Build hierarchy
var tree = new List<TreeViewModel>();
foreach (var item in list)
{
var nodeList = item.ParentId == null ? tree, nodeById[item.ParentId.Value].Children;
nodeList.Add(nodeById[item.Id]);
}

Add list of items to another object as a list where two values are equal

I have 2 objects as below:
public class object1
{
public int Object1ID { get; set; }
public string SomeValue { get; set; }
public List<object2> ListOfObject2 { get; set; }
}
public class object2
{
public int Object2ID { get; set; }
public string SomeValue2 { get; set; }
public int Object1LinkedID { get; set; }
}
Object1ID and Object2ID are unique ids.
I populate both of them as lists (so I have a list of Object1s and a list of Object2s).
List<Object1> listObject1 = new List<Object1>();
List<Object2> listObject2 = new List<Object2>();
I'd like to add all of the Object2s to Object1 where Object1LinkedID is equal to Object1. This can be into a new Object or just an update to original Object1 list.
This should work:
var groups = listObject2.GroupBy(o2 => o2.Object1LinkedID);
foreach(var o1Group in groups)
{
object1 o1 = listObject1.Where(o => o.Object1ID == o1Group.Key).First();
o1.ListOfObject2.AddRange(o1Group);
}
var query = from o1 in listObject1
join o2 in listObject2
on o1.Object1ID equals o2.Object1LinkedID
into go2
select new {O1 = o1, O2Coll = go2};
foreach (var rel in query)
{
rel.O1.ListOfObject2.AddRange(rel.O2Coll);
}
or
foreach (var object1 in listObject1)
{
int o1Id = object1.Object1ID;
object1.ListOfObject2.AddRange(listObject2.Where(o => o.Object1LinkedID == o1Id));
}

Categories

Resources