C# Linq All Condition - c#

I have a list of codes as follows
public Code{
int id;
string Description;
}
List<Code> AllCodes;
I have a list of selected codes from a different source.
var relatedCodes = //gets the list of int 'id's from a different source.
Using linq, I need to join AllCodes and relatedCodes so that the resultant list contains all the Code elements of the given ids. It is known that all the int values in relatedCodes are valid ids in AllCodes. [relatedCodes is an int array]
result = //how to write the linq expression?
I was trying something like this but it throws error
result = AllCodes.All(x => x.Code==relatedCodes);

First of all there is nothing to do with Join. Question is briefly How can I get the Codes of which relatedCodes contains the id?. You can use Where to filter your list.
var result = AllCodes.Where( c=> relatedCodes.Contains(c.id));

List<Code> result = AllCodes.Where(x => relatedCodes.Contains(x.id)).ToList();

EDIT:
Since relatedCodes is of type int[] (I used an array of type Code) the solution looks slightly different, but not by too much:
var relatedCodes = new int[2] { 2, 4 };
var joinedCodes = from ac in AllCodes
join rc in relatedCodes on ac.Id equals rc
select ac;
ORIGINAL answer
One possibility is to use join:
void Main()
{
var AllCodes = new List<Code>()
{
new Code() {Id = 1, Description="Foo1"},
new Code() {Id = 2, Description="Bar2"},
new Code() {Id = 3, Description="Foo3"},
new Code() {Id = 4, Description="Bar4"}
};
var relatedCodes = new Code[2]
{
new Code() {Id = 2, Description="Bar2"},
new Code() {Id = 4, Description="Bar4"}
};
var joinedCodes = from ac in AllCodes
join rc in relatedCodes on ac.Id equals rc.Id
select ac;
joinedCodes.Dump();
}
// Define other methods and classes here
public class Code{
public int Id { get; set; }
public string Description { get; set; }
}
Ouput:

Related

Differences between two models

Is there a way to compare 2 models and only show the differences, for example what has been updated, added or deleted?
For example, in the models below, I have created a number of Sample models:
var grocers1 = new List<Grocer>();
var grocer1 = new Grocer
{
Id = 1,
Expenditure = 500,
Name = "Bob"
};
grocers1.Add(grocer1);
var grocers2 = new List<Grocer>();
var grocer2 = new Grocer
{
Id = 1,
Expenditure = 300,
Name = "Bob"
};
grocers2.Add(grocer2);
var fruits = new List<Fruit>();
var fruit1 = new Fruit();
fruits.Add(fruit1);
var orders1 = new List<Order>();
var order1 = new Order
{
Id = 1,
SampleId = 1,
Fruits = fruits
};
var order2 = new Order
{
Id = 1,
SampleId = 1,
Fruits = fruits
};
orders1.Add(order1);
orders1.Add(order2);
var orders2 = new List<Models.Documents.Order> {order1};
var sample = new Sample
{
Id = 1,
Date = Convert.ToDateTime("2018-10-23"),
Grocers = grocers1,
Orders = orders1
};
var changedSample = new Sample
{
Id = 1,
Date = Convert.ToDateTime("2018-10-22"),
Grocers = grocers2,
Orders = orders1
};
var otherChangedSample = new Sample
{
Id = 1,
Date = Convert.ToDateTime("2018-10-23"),
Grocers = grocers1,
Orders = orders2
};
So if I compare sample to changedSample it should just show the Date has changed from 2018-10-23 to 2018-10-22 and that the Expenditure has changed from 500 to 300.
Then if I was to compare sample to otherChangedSample it should show that order2 has been removed.
And then finally if I was to compare otherChangedSample to sample it would show that order 2 had been added.
I have tested with AutoMapper this is great for comparing the same base model, excluding lists, it nicely highlights the changes.
I then tried Compare-Net-Objects which is good, this time does take into account lists and highlights the changes, but only if the list count stays the same. It will identify the list count change but not tell you the values of what has been removed or the values of what has been added.
Any help would be much appreciated.
You can use reflection and extension method as well:
var sample = new Sample
{
Id = 1,
Date = Convert.ToDateTime("2018-10-23"),
Grocers = grocers1,
Orders = orders1
};
var otherChangedSample = new Sample
{
Id = 1,
Date = Convert.ToDateTime("2018-10-23"),
Grocers = grocers1,
Orders = orders2
};
class Variance
{
public string Prop { get; set; }
public object valA { get; set; }
public object valB { get; set; }
}
List<Variance> rt = sample.DetailedCompare(otherChangedSample);
using System.Collections.Generic;
using System.Reflection;
static class extentions
{
public static List<Variance> DetailedCompare<T>(this T val1, T val2)
{
List<Variance> variances = new List<Variance>();
FieldInfo[] fi = val1.GetType().GetFields();
foreach (FieldInfo f in fi)
{
Variance v = new Variance();
v.Prop = f.Name;
v.valA = f.GetValue(val1);
v.valB = f.GetValue(val2);
if (!v.valA.Equals(v.valB))
variances.Add(v);
}
return variances;
}
}
have you coded your model classes yourself? If not, then you have to deal with reflection (could be slow and you have to do a lot of programming to cover all data types), or with serialization (serialize as string and do a string compare).
If you can extend your classes, then I would add a method to every single class:
internal void TrackChange(T other, List<Change> changes)
This method in your class Sampe would look like:
void TrackChange(Sample other, List<Change> changes)
{
if (this.Id != other.Id) changes.add(new Change(...));
if (this.Date != other.Date) changes.add(new Change(...));
if (this.Grocers.count != other.Grocers.count) changes.add(new Change(...)); // number of items has changed
for (int i = 0; i < math.min(this.grocers.count, other.grocers.count); i++)
this.grocers[i].TrackChange(other.grocers[i], changes);
....
}
The Grocer class has its onwn TrackChange method. and so on.
This is some coding, but the most efficient and you can handle all cases yourself. for example if the order of grocers in your list does not mind, then you can iterate all grocers of this list and try to find the corresponding grocer in the others list (e.g. by Id) and call the TrackChange then.

Group by linq for nested objects

I am making a group by linq statement where i convert a single list of data into an list with a nested list. Here is my code so far:
[TestMethod]
public void LinqTestNestedSelect2()
{
// initialization
List<combi> listToLinq = new List<combi>() {
new combi{ id = 1, desc = "a", name = "A", count = 1 },
new combi{ id = 1, desc = "b", name = "A", count = 2 },
new combi{ id = 2, desc = "c", name = "B", count = 3 },
new combi{id = 2, desc = "d", name = "B", count = 4 },
};
// linq group by
var result = (from row in listToLinq
group new { des = row.desc, count = row.count } by new { name = row.name, id = row.id } into obj
select new A { name = obj.Key.name, id = obj.Key.id, descriptions = (from r in obj select new B() { des = r.des, count = r.count }).ToList() }).ToList();
// validation of the results
Assert.AreEqual(2, result.Count);
Assert.AreEqual(2, result[0].descriptions.Count);
Assert.AreEqual(2, result[0].descriptions.Count);
Assert.AreEqual(2, result[1].descriptions.Count);
Assert.AreEqual(2, result[1].descriptions.Count);
}
public class A
{
public int id;
public string name;
public List<B> descriptions;
}
public class B
{
public int count;
public string des;
}
public class combi
{
public int id;
public string name;
public int count;
public string desc;
}
This is fine if the objects are small like the example. However I will implement this for objects with a lot more properties. How can I efficiently write this statement so I don't have to write field names twice in my linq statement?
I would like to return the objects in the statement and I want something like:
// not working wishfull thinking code
var result = (from row in listToLinq
group new { des = row.desc, count = row.count } by new { name = row.name, id = row.id } into obj
select new (A){ this = obj.key , descriptions = obj.ToList<B>()}).ToList();
Background: I am re writing a web api that retrieves objects with nested objects in a single database call for the sake of db performance. It's basically a big query with a join that retrieves a crap load of data which I need to sort out into objects.
probably important: the ID is unique.
EDIT:
based on the answers so far I have made a solution which sort of works for me, but is still a bit ugly, and I would want it to be better looking.
{
// start part
return (from row in reader.AsEnumerable()
group row by row.id into grouping
select CreateA(grouping)).ToList();
}
private static A CreateA(IGrouping<object, listToLinq> grouping)
{
A retVal = StaticCreateAFunction(grouping.First());
retVal.descriptions = grouping.Select(item => StaticCreateBFunction(item)).ToList();
return ret;
}
I hope the StaticCreateAFunction is obvious enough for what it does. In this scenario I only have to write out each property once, which is what I really wanted. But I hope there is a more clever or linq-ish way to write this.
var result = (from row in listToLinq
group new B { des = row.desc, count = row.count } by new A { name = row.name, id = row.id } into obj
select new A { name = obj.Key.name, id = obj.Key.id, descriptions = obj.ToList() }).ToList();
You can add to each of the A and B classes a constructor that receives a combi and then it takes from it only what it needs. For example for a:
public class A
{
public A(combi c)
{
id = c.id;
name = c.name;
}
}
public class B
{
public B(combi c)
{
count = c.count;
des = c.desc;
}
}
Then your query can look like:
var result = (from row in listToLinq
group row by new { row.id, row.name } into grouping
select new A(grouping.First())
{
descriptions = grouping.Select(item => new B(item)).ToList()
}).ToList();
If you don't like the grouping.First() you can then override Equals and GetHashCode and then in the group by do by a new a with the relevant fields (which will be those in the Equals) and then add a copy constructor from a
Another way, in which you decouple the A/B classes from the combi is to extract the convert logic to a collection of static methods.

Extensible relational division in LINQ

In this example class IcdPatient represents a many-to-many relationship between a Patient table (not shown in this example) and a lookup table Icd.
public class IcdPatient
{
public int PatientId { get; set; }
public int ConditionCode { get; set; }
public static List<IcdPatient> GetIcdPatientList()
{
return new List<IcdPatient>()
{
new IcdPatient { PatientId = 100, ConditionCode = 111 },
new IcdPatient { PatientId = 100, ConditionCode = 222 },
new IcdPatient { PatientId = 200, ConditionCode = 111 },
new IcdPatient { PatientId = 200, ConditionCode = 222 },
new IcdPatient { PatientId = 3, ConditionCode = 222 },
};
}
}
public class Icd
{
public int ConditionCode { get; set; }
public string ConditionName { get; set; }
public static List<Icd> GetIcdList()
{
return new List<Icd>()
{
new Icd() { ConditionCode =111, ConditionName ="Condition 1"},
new Icd() { ConditionCode =222, ConditionName ="Condition 2"},
};
}
}
I would like for the user to be able to enter as many conditions as they want, and get a LINQ object back that tells them how many PatientIds satisfy that query. I've come up with:
List<string> stringFilteredList = new List<string> { "Condition 1", "Condition 2" };
List<int> filteringList = new List<int> { 111,222 };
var manyToMany = IcdPatient.GetIcdPatientList();
var icdList = Icd.GetIcdList();
/*Working method without joining on the lookup table*/
var grouped = from m in manyToMany
group m by m.PatientId into g
where g.Count() == filteringList.Distinct().Count()
select new
{
PatientId = g.Key,
Count = g.Count()
};
/*End*/
foreach (var item in grouped)
{
Console.WriteLine(item.PatientId);
}
Let's say that IcdPatient has a composite primary key on both fields, so we know that each row is unique. If we find the distinct number of entries in filteringList and do a count on the number of times a PatientId shows up, that means we've found all the people who have all conditions. Because the codes can be esoteric, I would like to do something like
let the user table in the ConditionName in type Icd and perform the same operation. I've not used LINQ this way a lot and I've gathered:
List<int> filteringList = new List<int> { 111,222 };
List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
filteringList.Distinct();
var manyToMany = IcdPatient.GetIcdPatientList();
var icdList = Icd.GetIcdList();
/*Working method without joining on the lookup table*/
var grouped = from m in manyToMany
join i in icdList on
m.ConditionCode equals i.ConditionCode
//group m by m.PatientId into g
group new {m,i} by new { m.ConditionCode }into g
where g.Count() == filteringList.Distinct().Count()
select new
{
Condition = g.Key.ConditionCode
};
/*End*/
but can't get anything to work. This is essentially a join on top of my first query, but I'm not getting what I need to group on.
You don't need to group anything in this case, just use a join and a contains:
List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
var patients =
from icd in Icd.GetIcdList()
join patient in IcdPatient.GetIcdPatientList() on icd.ConditionCode equals patient.ConditionCode
where stringFilteredList.Contains(icd.ConditionName)
select patient.PatientId;
Let's say that IcdPatient has a composite primary key on both fields, so we know that each row is unique. If we find the distinct number of entries in filteringList and do a count on the number of times a PatientId shows up, that means we've found all the people who have all conditions. Because the codes can be esoteric, I would like to do something like let the user table in the ConditionName in type Icd and perform the same operation.
I believe you're asking:
Given a list of ConditionCodes, return a list of PatientIds where every patient has every condition in the list.
In that case, the easiest thing to do is group your IcdPatients table by Id, so that we can tell every condition that a patient has by looking once. Then we check that every ConditionCode we're looking for is in the group. In code, that looks like:
var result = IcdPatient.GetIcdPatientList()
// group up all the objects with the same PatientId
.GroupBy(patient => patient.PatientId)
// gather the information we care about into a single object of type {int, List<int>}
.Select(patients => new {Id = patients.Key,
Conditions = patients.Select(p => p.ConditionCode)})
// get rid of the patients without every condition
.Where(conditionsByPatient =>
conditionsByPatient.Conditions.All(condition => filteringList.Contains(condition)))
.Select(conditionsByPatient => conditionsByPatient.Id);
In query format, that looks like:
var groupedInfo = from patient in IcdPatient.GetIcdPatientList()
group patient by patient.PatientId
into patients
select new { Id = patients.Key,
Conditions = patients.Select(patient => patient.ConditionCode) };
var resultAlt = from g in groupedInfo
where g.Conditions.All(condition => filteringList.Contains(condition))
select g.Id;
Edit: If you'd also like to let your user specify the ConditionName rather than the ConditionId then simply convert from one to the other, storing the result in filteringList, like so:
var conditionNames = // some list of names from the user
var filteringList = Icd.GetIcdList().Where(icd => conditionNames.Contains(icd.ConditionName))
.Select(icd => icd.ConditionCode);

EntityFramework / LinQ load entity from database to dto

I have a problem loading the correct data to a DTO using EF and linq.
From my DB I receive following example data:
1, 1, 1
1, 1, 2
1, 1, 3
2, 1, 4
2, 1, 5
etc.
I want to load these data in a DTO which should look like this:
int, int, ICollection<int>
so for the example data:
new MyDto(1, 1, new List<int> { 1, 2, 3 });
new MyDto(2, 1, new List<int> { 4, 5 });
This is my linq query
var result = (from adresses in context.Adress
join person in context.Person on adresses.PersonId equals person.Id
select new MyObj { Id1 = adresses.Id1, Id2 = adresses.Id2, PersonId = person.Id })
But it is wrong, since it doesn't group by Id1 and Id2 and doesn't put the personIds in the list...
Could you please tell me how I can achieve this?
Pivot data using Linq is a better way. You can take look at this link:
Is it possible to Pivot data using LINQ
To answer your question, below is an example:
var result = (from adresses in context.Adress
join person in context.Person on adresses.PersonId equals person.Id
group address by address.Id1 into gResult
select new{
Id1 = gResult.Key,
Id2 = gResult.Select(r => r.Id2).FirstOrDefault (),
Id3 = gResult.Select (r => r.Id3)
});
In your Address class, do you have a property for a Person instance so you're able to set up a relationship between the two classes? If so, the following query may get you the result set that you're looking for:
public class Address
{
public int Id1 { get; set; }
public int Id2 { get; set; }
public virtual Person Person { get; set; }
}
public void Foo()
{
IEnumerable<MyObj> = context.Address.Select(x => new {
Id1 = x.Id1,
Id2 = x.Id2,
PersonId = x.Person.Id
});
}
Thanks for the good answers of you guys, I could finally work it out :-)
var result = from tuple in (from address in context.Adresses
join person in context.Persons on address.PersonId equals person.Id
select new { person.Id, address.Id1, address.Id2})
group tuple by new { tuple.Id1, tuple.Id2 } into myGrouping
select
new MyObj
{
Id1 = myGrouping.Key.Id1,
Id2 = myGrouping.Key.Id2,
PersonIds = myGrouping.Select(x => x.PersonId).Distinct()
};

Use the Linq Count

I want to show OrderDetails Count near the orders information in the grid but in the select Unit i can only select the Key and Count. What is the way to select the orders information?
var Q = from Data in Context.Orders
join D2 in Context.OrderDetails on Data.OrderID equals D2.OrderID
group Data by Data.OrderID into grouped
select new
{
grouped=g.Key,
Count = grouped.Count()
};
You can group it by whole order entity like
var Q = from Data in Context.Orders
join D2 in Context.OrderDetails on Data.OrderID equals D2.OrderID
group Data by Data into grouped
select new
{
OrderId = grouped.Key.OrderId,
OrderDate = grouped.Key.OrderDate
Shipping = grouped.Key.Shipping
.
.
.
Count = grouped.Count()
};
EDIT Linqpad program for similar query on in memory collection of objects
void Main()
{
var orders = new List<Order>{
new Order{OrderId = 1, DeliverIn = 5},
new Order{OrderId = 2, DeliverIn = 6},
new Order{OrderId = 3, DeliverIn = 5},
};
var lines = new List<OrderLine>{
new OrderLine{LineId = 1, OrderId = 1, ProductId = 1},
new OrderLine{LineId = 2, OrderId = 1, ProductId = 2},
new OrderLine{LineId = 3, OrderId = 1, ProductId = 3},
new OrderLine{LineId = 4, OrderId = 2, ProductId = 1},
new OrderLine{LineId = 5, OrderId = 2, ProductId = 3},
new OrderLine{LineId = 6, OrderId = 2, ProductId = 4},
};
var query = from o in orders join l in lines on
o.OrderId equals l.OrderId
group o by o into grouped
select new
{
Count = grouped.Count(),
grouped.Key.OrderId,
grouped.Key.DeliverIn
};
Console.WriteLine(query);
}
// Define other methods and classes here
public class Order
{
public int OrderId{get;set;}
public int DeliverIn{get;set;}
}
public class OrderLine
{
public int LineId{get;set;}
public int OrderId{get;set;}
public int ProductId{get;set;}
}
and if you don't have linq pad simply go and grab it from their site. It is simply awesome.
Check out IGrouping documentation on MSDN.
public interface IGrouping<out TKey, out TElement> : IEnumerable<TElement>,
IEnumerable
Pay attention to IEnumerable. Count is just an extension method of IEnumerable. You can easily Select from grouping or loop through it.
For example:
var Q = from Data in Context.Orders
join D2 in Context.OrderDetails on Data.OrderID equals D2.OrderID
group Data by Data.OrderID into grouped
select new
{
grouped=g.Key,
Count = grouped.Count(),
Orders = grouped.ToArray()
//you can also just return grouped itself to support lazy queries
};
Just flatten them into array or list and then get its count.
select new
{
Key = g.Key,
Orders = grouped.ToArray()
};
Then get count:
int count = result.Orders.Count; // Property of an array.

Categories

Resources