how to get data from list use c# and Linq - c#

I have classes
public class DevicePart
{
public int Id {get;set;}
public string Name {get;set;}
public int Distance {get;set;}
}
public class Device
{
public int ID {get;set;}
public string Name {get;set;}
public List<DevicePart> Parts {get;set;}
}
public class Data
{
public int Id{get;set;}
public string Name{get;set;}
public int ParentId{get;set;}
public int Distance{get;set;}
}
and I have list with Data:
1;Phone;0;0
2;TV;0;0
3;battery;1;5
4;button;1;3
5;webcam;2;5
how can I create optimal and faster linq query(or recursion procedure) to create object List<Device> from my Data list

Try this:
var data = new List<Data>()
{
new Data() { Id = 1, Name = "Phone", ParentId = 0, Distance = 0 },
new Data() { Id = 2, Name = "TV", ParentId = 0, Distance = 0 },
new Data() { Id = 3, Name = "battery", ParentId = 1, Distance = 5 },
new Data() { Id = 4, Name = "button", ParentId = 1, Distance = 3 },
new Data() { Id = 5, Name = "webcam", ParentId = 2, Distance = 5 },
};
var lookup = data.ToLookup(x => x.ParentId);
var devices =
lookup[0]
.Select(x => new
{
ID = x.Id,
x.Name,
Parts =
lookup[x.Id]
.Select(y => new
{
y.Id,
y.Name,
y.Distance,
})
.ToList(),
})
.ToList();
It gives me this:

Related

Filter List inside List Linq

I have list say list of customers and inside each list there is another list of orders
Class Customer
{
int ID,
string Name
List<Order> orders
}
Class Order{
int ID,
string Name
}
Also have a integer list of filteredorderIds = {1,2,3,4}
I want to filter the list of customers who has got orderIds from filteredorderIds list.
So far I am stuck at query like
var filteredCustomers = Customers.Where(x => x.Orders.Any(filteredorderIds.contains(y => y.Id)));
please give credit to #Johnathan Barclay, since he posted faster than i typed example
void Main()
{
var customers = new List<Customer>(){
new Customer(){
ID =1,
Name = "Cust1",
orders = new List<Order>(){
new Order(){ID = 4, Name = "o11"},
new Order(){ID = 5, Name = "o12"},
new Order(){ID = 6, Name = "o13"}
}
},
new Customer(){
ID = 2,
Name = "Cust2",
orders = new List<Order>(){
new Order(){ID = 3, Name = "o21"},
new Order(){ID = 7, Name = "o22"},
new Order(){ID = 8, Name = "o23"}
}
}
};
customers.Where(w =>
w.orders.Any(w => filteredorderIds.Contains(w.ID))
).Dump();
}
List<int> filteredorderIds = new List<int>() { 1, 2, 3, 4 };
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
public List<Order> orders { get; set; }
}
public class Order
{
public int ID { get; set; }
public string Name { get; set; }
}

How should I access HttpContext from a model in .NetCore2?

I want to use the Dev Express AspxLtreeList control in my UI and bind it to data from a .NetCore2 API
I am a fair newbie to both ASP and .NetCore
Can I , and if so how do I translate the following code to .NetCore?
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TreeListDragDropMultipleNodes.Models
{
public class Data
{
public int ID { set; get; }
public int ParentID { set; get; }
public string Title { set; get; }
}
public static class DataHelper
{
public static List<Data> GetData()
{
List<Data> data = HttpContext.Current.Session["Data"] as List<Data>;
if (data == null)
{
data = new List<Data>();
data.Add(new Data { ID = 1, ParentID = 0, Title = "Root" });
data.Add(new Data { ID = 2, ParentID = 1, Title = "A" });
data.Add(new Data { ID = 3, ParentID = 1, Title = "B" });
data.Add(new Data { ID = 4, ParentID = 1, Title = "C" });
data.Add(new Data { ID = 5, ParentID = 2, Title = "A1" });
data.Add(new Data { ID = 6, ParentID = 2, Title = "A2" });
data.Add(new Data { ID = 7, ParentID = 2, Title = "A3" });
data.Add(new Data { ID = 8, ParentID = 3, Title = "B1" });
data.Add(new Data { ID = 9, ParentID = 3, Title = "B2" });
data.Add(new Data { ID = 10, ParentID = 4, Title = "C1" });
data.Add(new Data { ID = 11, ParentID = 8, Title = "B1A" });
data.Add(new Data { ID = 12, ParentID = 8, Title = "B1B" });
HttpContext.Current.Session["Data"] = data;
}
return data;
}
public static void MoveNodes(int[] nodeKeys, int parentID)
{
var data = GetData();
var processedNodes = data.Join(nodeKeys, x => x.ID, y => y, (x, y) => x);
foreach(var node in processedNodes)
{
if (processedNodes.Where(x => x.ID == node.ParentID).Count() == 0)
{
if (node.ParentID == 0)
{
MakeParentNodeRoot(parentID);
}
node.ParentID = parentID;
}
}
}
public static void MoveNode(int nodeID, int parentID)
{
var data = GetData();
var node = data.Find(x => x.ID == nodeID);
if (node.ParentID == 0)
{
MakeParentNodeRoot(parentID);
}
node.ParentID = parentID;
}
public static void MakeParentNodeRoot(int id)
{
GetData().Find(x => x.ID == id).ParentID = 0;
}
}
}
You will need to find a way inject IHttpContextAccessor into the dependent class as HttpContext.Current is not available in .net-core.
To convert the current code first refactor the helper to not be static and it should also be backed by an abstraction/interface
public interface IDataHelper {
List<Data> GetData();
void MoveNodes(int[] nodeKeys, int parentID);
void MoveNode(int nodeID, int parentID);
void MakeParentNodeRoot(int id);
}
Have the class follow explicit dependency via constructor injection for IHttpContextAccessor
public class DataHelper : IDataHelper {
private readonly IHttpContextAccessor accessor;
public DataHelper(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public List<Data> GetData() {
List<Data> data = accessor.HttpContext.Session.Get<List<Data>>("Data");
if (data == null) {
data = new List<Data>();
data.Add(new Data { ID = 1, ParentID = 0, Title = "Root" });
data.Add(new Data { ID = 2, ParentID = 1, Title = "A" });
data.Add(new Data { ID = 3, ParentID = 1, Title = "B" });
data.Add(new Data { ID = 4, ParentID = 1, Title = "C" });
data.Add(new Data { ID = 5, ParentID = 2, Title = "A1" });
data.Add(new Data { ID = 6, ParentID = 2, Title = "A2" });
data.Add(new Data { ID = 7, ParentID = 2, Title = "A3" });
data.Add(new Data { ID = 8, ParentID = 3, Title = "B1" });
data.Add(new Data { ID = 9, ParentID = 3, Title = "B2" });
data.Add(new Data { ID = 10, ParentID = 4, Title = "C1" });
data.Add(new Data { ID = 11, ParentID = 8, Title = "B1A" });
data.Add(new Data { ID = 12, ParentID = 8, Title = "B1B" });
accessor.HttpContext.Session.Set("Data", data);
}
return data;
}
public void MoveNodes(int[] nodeKeys, int parentID) {
var data = GetData();
var processedNodes = data.Join(nodeKeys, x => x.ID, y => y, (x, y) => x);
foreach(var node in processedNodes) {
if (processedNodes.Where(x => x.ID == node.ParentID).Count() == 0) {
if (node.ParentID == 0) {
MakeParentNodeRoot(parentID);
}
node.ParentID = parentID;
}
}
}
public void MoveNode(int nodeID, int parentID) {
var data = GetData();
var node = data.Find(x => x.ID == nodeID);
if (node.ParentID == 0) {
MakeParentNodeRoot(parentID);
}
node.ParentID = parentID;
}
public void MakeParentNodeRoot(int id) {
GetData().Find(x => x.ID == id).ParentID = 0;
}
}
Some additional extension would be needed to store the data in the session
//Extensions used to stores complex objects as JSON string in session
public static class SessionExtensions {
public static void Set(this ISession session, string key, object value) {
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T Get<T>(this ISession session, string key) {
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
Configure the service collection to allow the needed dependencies to be resolved when requested.
services.AddScoped<IDataHelper, DataHelper>();
services.AddHttpContextAccessor();//IHttpContextAccessor is not added by default.
Any class that was dependent on the data helper would now also need to be refactored to depend on its abstraction.
This allows the code to be cleaner and more manageable as it will be decoupled from static implementation concerns.

The most frequently occurring item in a list

I have a list in this table
public class Fruits
{
public int ID { get; set; }
public string Name{ get; set; }
}
I want to know what are the most frequent fruit in this table what is the code that appears to me this result
I am use
var max = db.Fruits.Max();
There is an error in that?
Try
public class Fruits
{
public int ID { get; set; }
public string Name{ get; set; }
}
var Val = fruitList.GroupBy(x => x.ID,
(key, y) => y.MaxBy(x => x.ID).value)
As Drew said in the comments, you want to GroupBy on the value that you care about (I did Name, since ID tends to be unique in most data structures) and then OrderByDescending based on the count.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var fruits = new List<Fruit> { new Fruit { ID = 1, Name = "Apple" }, new Fruit { ID = 2, Name = "Apple" }, new Fruit { ID = 3, Name = "Pear" } };
var most = fruits.GroupBy(f => f.Name).OrderByDescending(group => group.Count());
Console.WriteLine(most.First().Key);
}
}
public class Fruit
{
public int ID { get; set; }
public string Name{ get; set; }
}
If you want to get the name of the item that exists most in your list, first find the id that is most occurring:
var fruitAnon = fruits
.GroupBy(item => item.ID)
.Select(item => new {
Key = item.Key,
Count = item.Count()
})
.OrderByDescending(item => item.Count)
.FirstOrDefault();
This will return an anonymous object that will have the most frequent id, and the count represents the number of times it exists in the list. You can then find that object's name:
var fruit = fruits.FirstOrDefault(x => x.ID == fruitAnon.Key);
If you had a list like this:
List<Fruits> fruits = new List<Fruits>() {
new Fruits { ID = 1, Name = "Apple" },
new Fruits { ID = 1, Name = "Apple" },
new Fruits { ID = 2, Name = "Orange" },
new Fruits { ID = 2, Name = "Orange" },
new Fruits { ID = 2, Name = "Orange" },
new Fruits { ID = 2, Name = "Orange" }
};
Then:
Console.WriteLine(fruit.Name);
Would print Orange.

LINQ group list and combine collections

Given these classes:
public class Employee
{
public int EmployeeId { get; set; }
public int GroupId { get; set; }
public List<Plans> Plans { get; set; }
}
public class Plan
{
public int PlanYearId { get; set; }
public string Name { get; set; }
}
And given a setup like so:
var employees = new List<Employee> {
new Employee {
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId = 1111,
Name = "Benefit 1"
}}};
new Employee {
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId= 2222,
Name = "Benefit 2"
},
new Plan {
PlanReferenceId= 2222,
Name = "Benefit 3"
}}}};
How can I use LINQ to group these employees by both EmployeeId and GroupId and then combine the two List<Plan> properties so that i would end up with something like this:
var employee = new Employee
{
EmployeeId = 1,
GroupId = 1,
Plans = new List<Plan> {
new Plan {
PlanReferenceId = 1111,
Name = "Benefit 1"
},
new Plan {
PlanReferenceId = 2222,
Name = "Benefit 2"
},
new Plan {
PlanReferenceId = 2222,
Name = "Benefit 3"
}
}
}
Just use combination of GroupBy and SelectMany:
var result = employees
.GroupBy(e => new { e.EmployeeId, e.GroupId })
.Select(g => new Employee
{
EmployeeId = g.Key.EmployeeId,
GroupId = g.Key.GroupId,
Plans = g.SelectMany(e => e.Plans).ToList()
}).ToList();

Map value to item from list and add the new value to the same list C#

I have an Array of colors viz.
var colorPallete = new string[]{color1, color2, color3, color4, color5};
I also have a list of objects which contains an ID.
eg. var previousList<MyModel> = new List<MyModel>();
MyModel.cs
public class MyModel()
{
public int ID {get; set;}
public string Class{get; set;}
public string Name {get; set;}
public string Color {get; set;}
}
I want to assign the objects with same ID with a certain color. And then add the assigned color as a new value to the list.
for eg:
Previous list :-
ID :1
Name: abc
Class: Senior
ID :2
Name: xyz
Class: Medium
ID :3
Name: pqr
Class: junior
ID :1
Name: mno
Class: junior
New List :-
ID :1
Name: abc
Class: Senior
Color :color1
ID :2
Name: xyz
Class: Medium
Color :color2
ID :3
Name: pqr
Class: junior
Color :color3
ID :1
Name: mno
Class: junior
Color :color1
This works for me:
var colorPallete = new string[]
{
"color1", "color2", "color3", "color4", "color5",
};
var previousList = new []
{
new { ID = 1, Name = "abc", Class = "Senior", },
new { ID = 2, Name = "xyz", Class = "Medium", },
new { ID = 3, Name = "pqr", Class = "junior", },
new { ID = 1, Name = "mno", Class = "junior", },
};
var newList =
previousList
.Select(x => new
{
x.ID,
x.Name,
x.Class,
Color = colorPallete.ElementAtOrDefault(x.ID - 1),
})
.ToList();
I get this result:
With the question update providing the class MyModel the code can then be written like so:
var colorPallete = new string[]
{
"color1", "color2", "color3", "color4", "color5",
};
var previousList = new List<MyModel>()
{
new MyModel() { ID = 1, Name = "abc", Class = "Senior", },
new MyModel() { ID = 2, Name = "xyz", Class = "Medium", },
new MyModel() { ID = 3, Name = "pqr", Class = "junior", },
new MyModel() { ID = 1, Name = "mno", Class = "junior", },
};
var newList =
previousList
.Select(x => new MyModel()
{
ID = x.ID,
Name = x.Name,
Class = x.Class,
Color = colorPallete.ElementAtOrDefault(x.ID - 1),
})
.ToList();
Which gives:
Now, this approach produces a new list keeping the old list and the old objects intact. Generally this is what you should try to do. It's best to mutate objects only when you know that's what they're designed to do.
So it becomes possible to do an in-place update of the original list like so:
previousList.ForEach(x => x.Color = colorPallete.ElementAtOrDefault(x.ID - 1));
This results in modifying the previousList objects without creating a newList.
If you are using List<T> (not IEnumerable<T>) and you don't want to create a new list, but need to update values in the existing list instead, you can do it with the single query. There are three ways to process your scenario (A, B, C):
var colorPallete = new string[]
{
"Red", "Green", "Blue"
};
var list = new List<MyModel>()
{
new MyModel() { ID = 1, Name = "model1", Class = "A", },
new MyModel() { ID = 1, Name = "model11", Class = "AA", },
new MyModel() { ID = 2, Name = "model2", Class = "B", },
new MyModel() { ID = 3, Name = "model3", Class = "C", },
new MyModel() { ID = 4, Name = "model4", Class = "D", },
new MyModel() { ID = 5, Name = "model5", Class = "E", },
};
//A. This code assigns null for unknown IDs
//I.e. if (ID > 0 && ID < colorPallete.Length) then color will be picked from colorPallete[],
//else it will be null
list.ForEach(x => x.Color = colorPallete.ElementAtOrDefault(x.ID - 1));
//B. This code apply some default color for unknown IDs
//I.e. if (ID > 0 && ID < colorPallete.Length) then color will be picked from colorPallete,
//else it will be "DefaultColor"
list.ForEach(x => x.Color = colorPallete.ElementAtOrDefault(x.ID - 1) ?? "DefaultColor");
//C. This code can assign the same color to models with different IDs,
//but models with identical IDs always will have identical color
list.ForEach(x => x.Color = colorPallete.ElementAtOrDefault((x.ID - 1) % colorPallete.Length));
I would create a class for the objects with a color property like this:
public class MyClass
{
public int ID { get; set; }
public string Name { get; set; }
public string Class { get; set; }
public string Color { get; set; } // Nullable
}
And for the colors I would create another class with an ID to compare with the ID of MyClass:
public class MyColor
{
public int ID { get; set; }
public string Color { get; set; }
}
For each color in colorPalette you would assign an ID that matches the ID of the list of MyClass.
So at first the color from MyClass would be null. And then you could loop over the list of MyClass:
foreach (MyClass myClass in myClassList)
{
myClass.Color = colorPalette.FirstOrDefault(col => col.ID = myClass.ID);
}
Or without an ID in Color class (comparing the names of the variables which is not a beautiful solution):
foreach (MyClass myClass in myClassList)
{
myClass.Color = colorPalette.FirstOrDefault(col => int.Parse(nameof(col.Color).Replace("color", "")) == myClass.ID);
}

Categories