Duplicate values using linq - c#

I have the Input format in following way
S.no Name wages
1 Tom $200
1 Tom $300
1 Tom $400
2 Rob $500
2 Rob $600
Result set should be in the following way
Name OriginalWage DuplicateWage
Tom $200 $300
Tom $200 $400
Rob $500 $600
I should leave the first record and take the duplicate records into count .Here the original wages is the wage of the first distinct record.
How can i accomplish the result set using linq.
This is the one i tried so far
//Get duplicate values
Dim Duplicates = wageRecordList.GroupBy(Function(w) w.serialnumber).Where(Function(d) d.Count > 1)
//load duplicates to a list
lstDuplicateRecords=Duplicates
//Read list--This one is a hard coded sort of thing and works only for one set of duplicate values
lstResult = (From duplicateRecords In lstDuplicateRecords.Skip(1) Select serialnumber= duplicateRecords.serialnumber, Name= duplicateRecords.Name, OriginalWages= CType(lstDuplicateRecords(0).Wages, String), _
DuplicateWages = CType(duplicateRecords.wages, String))

You can make something like this
var groupedUsers = from user in users
group user by user.User into userGroup
select new
{
User = userGroup.Key,
userHobies =
userGroup.Aggregate((a, b) =>
new { User = a.User, Hobby = (a.Hobby + ", " + b.Hobby) }).Hobby
}
;
foreach (var x in groupedUsers)
{
Debug.WriteLine(String.Format("{0} {1}", x.User, x.userHobies));
}
code is not mine and has been taken from: Use LINQ to concatenate multiple rows into single row (CSV property)
this link might be helpful too
EDITED
Sorry, misunderstood you question
something like this can do the trick
var query = from sal in _yourcontext
join salmin in ( from sal1 in _yourcontext
group sal1 by sal1.name into group
select new{
Name = group.Key
MinSal = group.Min(sal1=>sal1.Salary))
}
on sal.Name equals salmin.Name into result
where sal.Salary != salmin.MinSal
select new{ salmin.Name,salmin.MinSal,sal.Salary }

I managed to get the result set you wanted (proved a nice challenge):
It is assuming that the first record it finds for an employee is the original wage however...
var result = from employeeWages in GetEmployees().GroupBy(e => e.Name)
from duplicateWage in employeeWages.Skip(1).Select(e => e.Wage)
select new
{
Name = employeeWages.Key,
OriginalWage = employeeWages.First().Wage,
DuplicateWage = duplicateWage
};
A full LinqPad script is here for testing: http://share.linqpad.net/wgxcns.linq
Example Result

Related

spliting a string using linq queries in C# from fist name to last name

The name would be a single string like string NAME="BILL GATES"
the plan is to order it in the last name first then the first name last so
Gates Bill, what's happening is that it's coming out as first and last.
var Q4 = from p in persons
orderby p.Name.Split()[1], p.Name.Split()[0]
select p;
foreach (var Item in Q4)
{
Console.WriteLine($"{Item}");
}
As #BACON pointed out in the comments, you need to select the new name(last name + firstname) after you sort with orderby. Additionally, this can be made easier storing the split names once with the let clause, which is also more efficient since you don't need to re-split the names every time you want to use them.
var Q4 = from p in persons
let names = p.Name.Split()
orderby names[1], names[0]
select new { Name = $"{names[1]} {names[0]}" };
The above also uses $ - string interpolation to insert the last name before the first name into a space separated string. You can also use names[1] + " " + names[0] here if you want to.
orderby will not replace the content in "Name". If you want change the content, use select new:
var Q4 = from p in persons
select new
{
name = p.name.Split()[1] +" "+ p.name.Split()[0]
};
foreach(var Item in Q4)
{
Console.WriteLine($"{Item}");
}

Linq Grouping items by property

I'm trying to group an object by one property (State). The end goal is to have a list. And within each list is an object consisting of two properties. I have data that looks like the following...
State Name ID
CA John 12
CA Kevin 13
CA Joe 14
AZ Sally 15754
AZ Stuart 1263
TN Sam 1211
How would one go about using linq to make this a list of object 'People' consisting of a person's name and ID grouped by state? This is what I've tried...but it's not working
var result = from groupOne in dataset
group groupOne by OneGroup.State into g
select new People() { People = g.ToList() }.ToList();
Why are you grouping by OneGroup.State, when OneGroup is not a part of the query?
That one should do the trick:
var result = from groupOne in dataset
group groupOne by groupOne.State into g
select new {
State = g.Key,
People = g.Select(x => new { x.Name, x.ID })
};
It returns anonymous types, but you can easily change it to return your class objects if you need.

How can I use sum with group by in LINQ?

I have the following many companies. Some of the companies have subjects and others do not. Something like this:
CompanyID Subjects
1 2
2 4
3 1
4 0
I am trying to create a LINQ report that will give me this information. This is what I have so far. It correctly does an outer join so that even companies with no subjects are include in the list. Once I have that data then I group the date by company title. The problem is that the last select does not work correctly. Can someone suggest how I can get the sum. I was able to use count() but I need a sum as the way I have set things up is that when there are no subjects a value of 0 goes into Subjects and where there is 1 a value of one goes there. So by summing the count of Subjects at each break in the group I should be able to find out how many subjects are assigned to the company.
var test1 = from c in companies
join s in subjects
on "0000" + c.RowKey equals s.PartitionKey into outer
from s in outer.DefaultIfEmpty()
select new
{
Title = c.Title,
Subjects = ((s == null) ? 0 : 1)
} into split
group split by split.Title into g
select new
{
Title = g.Key,
total = g.sum(s => s.Subjects)
};
You wrote the "sum" method without the capital "s". C# is case sensitive, so I think that's your problem, if you're getting a compile error.
Otherwise include the actual result of your query and what you expect, so we can compare it and try to find the problem.

Write this into one linq query?

This has its root into another question I asked, that solved a part of this problem -
Convert this code to LINQ?
Now I am trying to write the entire logic in the following manner -
var divisions = (
from DataRow row in results.Rows
let section = row["SECTION"].ToString()
orderby section ascending
select section).Distinct();
string result = String.Empty;
foreach (string div in divisions)
{
result = String.Concat(result, div, Environment.NewLine);
var query =
from DataRow row in results.Rows
let remarks = row["REMARKS"].ToString()
let exam = row["EXAM_NAME"].ToString()
let rollno = row["ROLL_NO"].ToString()
let section = row["SECTION"].ToString()
where (remarks == "Passes" || remarks == "Promoted") &&
exam == "TOTAL" && section == div
orderby rollno
select rollno;
result = String.Concat(result,string.Join(" ", query.ToArray()),
Environment.NewLine);
}
Basically, the original datatable has a bunch of rows with various information including Division. I want to create a single string, for which every division appears on a new line, and below that the roll nos for that division are shown in comma separated fashion. Next division on next line, and so on. (here Section and division are interoperable terms).
Is there any elegant way to write this with one linq query, instead of having to loop through the results of the first query?
EDIT:
Data (not mentioning the other columns that are used in filter conditions)
Roll_no Section.. other cols
001 A
002 A
001 B
003 A
004 B
006 B
This is what the output will look like - (roll no is unique only within a division, but that should not affect the logic in any way)
A
001 002 003
B
001 004 006
This will be like 'A\r\n001 002 003\r\nB\r\n001 004 006' when the string is in raw format.
Note, the above code works. I am just looking for a better approach.
There are two separate requirements you want to have implemented, and you should not try to merge them into a single thing. You 1. want to group the results togetter and 2. have specific needs for presentation.
Here is how you can do this:
var query =
from DataRow row in results.Rows
// here the query stuff you already had
select new { rollno, section, exam, remarks };
// 1. Grouping
var groups =
from item in query
group item by item.section into g
select new
{
Section = g.Key,
Rollnos = g.Select(i => i.rollno).ToArray(),
};
// 2. Presentation
foreach (var group in groups)
{
Console.WriteLine(group.Section);
Console.WriteLine(string.Join(" ", group.Rollno));
}
It is possible to write one single query that also does part of the presentation for you, but this query would become very nasty and unreadable.

LINQ group by month question

I'm new to LINQ to SQL and I would like to know how to achieve something like this in LINQ:
Month Hires Terminations
Jan 5 7
Feb 8 8
Marc 8 5
I've got this so far, and I think there is something wrong with it but I'm not sure:
from term1 in HRSystemDB.Terminations
group term1 by new { term1.TerminationDate.Month, term1.TerminationDate.Year } into grpTerm
select new HiresVsTerminationsQuery
{
Date = Criteria.Period,
TerminationsCount = grpTerm.Count(term => term.TerminationDate.Month == Criteria.Period.Value.Month),
HiresCount = (from emp in HRSystemDB.Persons.OfType<Employee>()
group emp by new { emp.HireDate.Month, emp.HireDate.Year } into grpEmp
select grpEmp).Count(e => e.Key.Month == Criteria.Period.Value.Month)
});
Thanks in advance.
I'm not quite sure where does the Criteria.Period value come from in your sample query.
However I think you're trying to read both hires and terminations for all available months (and then you can easily filter it). Your query could go wrong if the first table (Termination) didn't include any records for some specified month (say May). Then the select clause wouldn't be called with "May" as the parameter at all and even if you had some data in the second table (representing Hires), then you wouldn't be able to find it.
This can be elegantly solved using the Concat method (see MSDN samples). You could select all termniations and all hires (into a data structure of some type) and then group all the data by month:
var terms = from t in HRSystemDB.Terminations
select new { Month = t.TerminationDate.Month,
Year = term1.TerminationDate.Year,
IsHire = false };
var hires = from emp in HRSystemDB.Persons.OfType<Employee>()
select new { Month = emp.HireDate.Month,
Year = emp.HireDate.Year
IsHire = true };
// Now we can merge the two inputs into one
var summary = terms.Concat(hires);
// And group the data using month or year
var res = from s in summary
group s by new { s.Year, s.Month } into g
select new { Period = g.Key,
Hires = g.Count(info => info.IsHire),
Terminations = g.Count(info => !info.IsHire) }
When looking at the code now, I'm pretty sure there is some shorter way to write this. On the other hand, this code should be quite readable, which is a benefit. Also note that it doesn't matter that we split the code into a couple of sub-queries. Thanks to lazy evalutation of LINQ to SQL, this should be executed as a single query.
I don't know if it shorter but you can also try this version to see if it works better with your server. I don't know exactly how these two answers turn into SQL statements. One might be better based on your indexs and such.
var terms =
from t in Terminations
group t by new {t.Month, t.Year} into g
select new {g.Key, Count = g.Count()};
var hires =
from p in Persons
group p by new {p.Month, p.Year} into g
select new {g.Key, Count = g.Count()};
var summary =
from t in terms
join h in hires on t.Key equals h.Key
select new {t.Key.Month, t.Key.Year,
Hires = h.Count, Terms = t.Count};

Categories

Resources