How to calculate property in a chained linq query - c#

Is it possible to compute 'on-the-fly' Division based on Department and JobTitle
with eventually applying some Transformations such as concatenating
in the chained linq query below ?
public static List<Developer> GetDevelopersData(List<Employee> employees)
{
List<Developer> developers =
employees.Where(x => x.Department == "Dev")
.Select(x => new Developer
{
Name = x.Name,
Department = x.Department,
JobTitle = x.Function,
Division = "Department" + "/" + "Function" // based on previous properties
}).ToList();
return developers;
}

I suppose Function and Departement are string type ?
List<Developer> developers =
employees.Where(x => x.Department == "Dev")
.Select(x => new Developer
{
Name = x.Name,
Department = x.Department,
JobTitle = x.Function,
Division = String.Concat(x.Function, "/", x.Department)
}).ToList();
return developers;

Unless I'm missing something, you could do:
Division = string.Format("{0}/{1}", x.Department, x.Function)
Assuming you just want the two properties concatenated into a string.

to compute on the fly, you can use let
(from x in employees
let MyFunction=String.Concat(x.Function, "/", x.Department)//you can use whatever you want here
select new Developer()
{
Name = x.Name,
Department = x.Department,
JobTitle = x.Function,
Division = x.MyFunction
}).ToList();

Related

How to sort data based on CreatedUtc Date using mongodb query in c#?

I want to sort the data based on CreatedUtc time. I have tried to use Reverse function, it seems to work out but still looking for some alternate option.
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).ToList().Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().ToList();
There are 2 things you need to concern:
You can sort the elements of a sequence by using OrderBy
You should not .ToList() when you have not done, So you might to read LINQ deferred (or immediate?) execution to have a better understanding.
As a result, your query should look like this
var result = _participantRepo.AsQueryable().Where(x => x.Id == ParticipantId).SelectMany(x =>
x.Relations).Where(x => x.UserId != AppUserId).Select(r => new RelationVM
{
IsOwner = r.UserId == participant.CreatedByUserId,
FirstName = r.FirstName,
LastName = r.LastName,
Email = r.Email,
UserId = r.UserId,
RelationType = r.RelationType,
Role = r.Role,
IsAccepted = r.IsAccepted,
AvatarUrl = r.AvatarUrl,
CreatedUtc = r.CreatedUtc
}).Reverse().OrderBy(g => g.CreatedUtc).ToList();
How about .OrderBy(g => g.CreatedUtc) ?

Putting one column from a multi column query into a list

I am trying to put the Column LANS from this multi column query into a list.
And the First and Last name into a separate list.
I just can't figure out how to make it work.
CODE:
//Resource
var ResourceFilter = _context.INT_CertificationsXREF.Include(i => i.RIM_Resource)
.Where(i => i.RIM_Resource.LAN == i.RIM_Resource.LAN)
.Where(i => i.Approved == true)
.Where(i => i.RIM_Resource.LAN != UserInformation.Globals.LANID)
.Select( i => i.RIM_Resource.FirstName + i.RIM_Resource.LastName + i.RIM_Resource.LAN)
.Distinct()
.ToList();
var ResourceFilterNames = ResourceFilter.RIM_Resource.Firstname + RIM_Resource.LastName.ToList();
var ResourceFilterLANS = ResourceFilter.RIM_Resource.LAN.ToList();
Desired OutPut
ResourceFilterNames = Firstname" "Lastname, Firstname" "Lastname, ect....
ResourceFilterLANS = NQ90, RE97, I3R9, ect.
The list also need to be in sync order wise.
If I understood your question...i think what you want is:
var ResourceFilter = _context.INT_CertificationsXREF.Include(i => i.RIM_Resource)
.Where(i => i.RIM_Resource.LAN == i.RIM_Resource.LAN)
.Where(i => i.Approved == true)
.Where(i => i.RIM_Resource.LAN != UserInformation.Globals.LANID)
.Select( i => new {
fullName = i.RIM_Resource.FirstName + " " + i.RIM_Resource.LastName,
Lan = i.RIM_Resource.LAN
})
.Distinct()
.ToList();
the you can retrieve the list of "fullNames" and "LANS" like this
List<string> fullNames = ResourceFilter.Select(x => x.fullName).ToList();
List<string> LANS = ResourceFilter.Select(x => x.Lan).ToList();
hope it helps
Based on your desired output I think this solution will work for you
var ResourceFilterNames= string.Join(",", ResourceFilter.Select(x => ( x.Firstname
+ " " + x.LastName )));
var ResourceFilterLANS = string.Join(",", ResourceFilter.Select(x=> x.Lan));
In order this solution to work you should delete Select from ResourceFilter or rewrite it like below:
.Select( i => new { i.RIM_Resource.FirstName, i.RIM_Resource.LastName, i.RIM_Resource.LAN})
I will use the following class as my test input:
public class MyData
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Lan { get; set; }
}
My first solution assumes that your combination of FirstName and LastName is unique.
To hold your two lists in sync I will use a dictionary:
// var resource = new List<MyData>();
var dictionary = resource.ToDictionary(r => r.FirstName + r.LastName, r => r.Lan);
My second solution assumes that they are not unique so you can use this:
var dictionary = new Dictionary<string, List<string>>();
foreach(var res in resource)
{
var key = res.FirstName + res.LastName;
List<string> value;
if ( dictionary.TryGetValue(key, out value))
{
value.Add(res.Lan);
}
else
{
dictionary[key] = new List<string> {res.Lan};
}
}

LINQ Get Latest Record from Multiple Records to List

I have a table as
StudentName / Classroom / GradeA / GradeB / GradeC / GradeDate
The students classrooms are fixed so that column never changes.
Each student has multiple GradeA, GradeB and GradeC values with different GradeDate.
public virtual IList<ClassroomDetail> GetLatestClassroomDetail(string classroom)
{
var query = from pc in _classroomDetailRepository.Table
where pc.Classroom == classroom
select pc;
var result = new List<ClassroomDetail>(query);
return result;
}
Above query returns everything and there are multiple same students in the list.
How can I only get latest values?
Tables:
ClassroomMaster
Id
UpdateDate
Classroom
ClassroomDetail
Id
Cm_Id (has foreign key with ClassroomMaster Id)
StudentName
GradeA
GradeB
GradeC
GradeDate
On Controller
var bdetail = _classroomService.GetLatestClassroomDetail(classroom).OrderBy(d => d.StudentName);
var model = new List<ClassroomDetail>();
foreach (var pr in bdetail)
{
model.Add(new ClassroomDetail
{
Id = pr.Id,
Classroom = pr.Classroom,
StudentName = pr.StudentName,
GradeA = pr.GradeA,
GradeB = pr.GradeB,
GradeC = pr.GradeC,
GradeDate = pr.GradeDate,
});
}
return PartialView(model);
It will solve your problem
var query = _classroomDetailRepository.Table
.Where(a => a.Classroom == classroom)
.Select(b => b.OrderByDescending(y => y.GradeDate).Take(1).FirstOrDefault());
I finally found the solution :D
public virtual IList<ClassroomDetail> GetLatestClassroomDetail(string classroom)
{
var query = _classroomDetailRepository.Table
.Where(z => z.Classroom == classroom)
.GroupBy(x => x.StudentName)
.Select(x => x.OrderByDescending(y => y.GradeDate).Take(1).FirstOrDefault());
var result = new List<BunkerPriceDetail>(query);
return result;
}

Combine two list data into single list C#

So i have following two list using linq.
List<One> one= A.Common
.Join(B.Common,
a => a.ID,
b=> b.ID,
(a, b) => new One
{
ID = b.PID,
Name = b.PCName,
LastName = a.LName
}).ToList();
List<One> two = (from c in D.Options
select new One
{
MainName = c.mName
}).ToList();
List<One> sn = one.Concat(two).ToList();
I am concating both list. But when i debug i am getting MainName as null in sn list.
How do i get data from both list in single list??
This is how you do it:
var sn = one.Zip(two, (x, y) => new One{
ID = x.ID,
Name = x.Name,
LastName = x.LastName,
MainName = y.MainName
});
You want the MainName property assigned for all the list values in List ONE ?
As from above code concatenation will join two list and the MainName will be not set for list one elements.
one.Concat(two)
Above line will just concat the both lists to one list elements.
You can use the LINQ Concat and ToList methods:
var mergedList = YourFirstList.Concat(YourSecondList)
.Concat(YourThirdList)
.ToList();
Edit:
one.Concat(two).Select(g => g.Aggregate((p1,p2) => new One
{
ID = p1.ID,
Name = p1.PCName,
LastName = p1.LName,
MainName = p2.mName
}));
more efficient ways to do this - the above will basically loop through all the entries, creating a dynamically sized buffer.
var mergedList = new List<One>(YourFirstList.Count +
YourSecondList.Count +
YourThirdList.Count);
mergedList.AddRange(YourFirstList);
mergedList.AddRange(YourSecondList);
mergedList.AddRange(YourThirdList);
AddRange is special-cased for ICollection<T> for efficiency.
You can use the Zip method.
one.Zip(two,(o1, o2) => new One()
{
ID = o1.ID,
Name = o1.PCName,
LastName = o1.LName,
MainName = o2.mName
});

Linq Lambda get two properties as string from aggretation

Inside a linq query to an anonymous select I want to concatenate strings from two properties.
For instance to find the full name of the oldest person in some grouping of persons.
var personsAndOldest = db.Persons.GroupBy(person => person.SomeThingThatCanBeGroupedForPerson).Select(a => new
{
FirstName = a.FirstOrDefault().FirstName,
LastName = a.FirstOrDefault().LastName,
BirthDate = a.FirstOrDefault().BirthDate,
FullnameOfOldes = a.Aggregate((pers1, pers2) => pers1.BirthDate > pers2.BirthDate ? pers1 : pers2).FirstName + " " //How do I get LastName of the old one (without using the full aggregate again)
});
Do I have to write the full aggregation again to get the LastName after the firstname and whitespace?
You could use a lambda statement in the Select:
var personsAndOldest = db.Persons.GroupBy(person => person.SomeThingThatCanBeGroupedForPerson).Select(a =>
{
var first = a.First();
var oldest = a.Aggregate((pers1, pers2) => pers1.BirthDate > pers2.BirthDate ? pers1 : pers2);
return new
{
FirstName = first.FirstName,
LastName = first.LastName,
BirthDate = first.BirthDate,
FullnameOfOldes = oldest.FirstName + " " + oldest.LastName)
};
});
You can do this as
var personsAndOldest = db.Persons
.GroupBy(person => person.SomeThingThatCanBeGroupedForPerson)
.Select(g => new
{
a = g.First(),
o = g.Aggregate((pers1, pers2) =>
pers1.BirthDate > pers2.BirthDate ? pers1 : pers2)
})
.Select(pair => new
{
FirstName = pair.a.FirstName,
LastName = pair.a.LastName,
BirthDate = pair.a.BirthDate,
FullnameOfOldes = pair.o.FirstName + " " + pair.o.LastName
});
You can use let to introduce new range variables.
You don't need to specify property name for anonymous type if it equals name of assigned property
I think OrderBy will find oldest person (but you can use aggregate and compare performance)
I believe that oldest person is one with minimal birth date, so you need to change aggregation to pers1.BirthDate < pers2.BirthDate ? pers1 : pers2
So
var personsAndOldest = from p in db.Persons
group p by p.SomeThingThatCanBeGroupedForPerson into g
let first = g.FirtOrDefault()
let oldest = g.OrderBy(x => x.BirthDate).FirstOrefault()
select
{
first.FirstName,
first.LastName,
first.BirthDate,
FullnameOfOldes = oldest.FirstName + " " + oldest.LastName
};

Categories

Resources