Linq, filter out multiples - c#

I have written a Search-function in my MVC-project, it matches a database.
The database have the struct like this:
Name - string (The name of the data)
SubName - string (the subname of the data)
SomeData - int (the actual data)
So if i have like 100 posts with a name and a specific subname with different values for the data. and then 100 posts more with the same name but a different subname.
Now when i search the database i use this linq-code;
var names = db.Graphs
.Where(r => r.Name.Contains(term))
.Take(5).Distinct()
.Select(r=> new {label = r.Name});
I thougth that that maby would get med 5 distinct answers, but it dosent...
I get five of the first 100 post, i would like to filter so that i take only uniqe name with subnames. So in the example above i would have revived 2 entrys.
Feel like i have tried everything and failed so any input would be appriciated.

var names = db.Graphs
.Where(r => r.Name.Contains(term))
.GroupBy(s=>s.Name).Take(5)
.Select(r => new { label = r.FirstOrDefault().Name });
You should apply Distinct() before Take().I hope this will help.

Related

LINQ - Comparing a search term with multiple entries against another string with multiple entries

I have a column called Title in the DB.
and i have a search term coming from the app.
What i have done so far is this:
var valsSearch = value.searchTerm.ToLower().Split(" ");
var results = ctx.Links.Select(x =>x.Title).Where(x => valsSearch.Contains(x)).ToList();
For example the Title in the DB might be "Ronaldo scores a hattrick" and the searchTerm may be "scores ronaldo"
How do i filter the results when comparing the Title in DB to the searchTerm?
The result should be that the searchTerm when separated are used to filter the values in the Title DB and if there's a match return the result.
Try this,
var valsSearch = value.searchTerm.ToLower().Split(" ");
var results = ctx.Links.AsEnumerable().Where(x => valsSearch.Any(y => x.Title.ToLower().Contains(y))).ToList();

Entity Framework - Query to obtain last 2 unique entries of a column and then their relevant data

I am new to entity framework and I am having difficulty coming up with a query. For the following situation.Say I have the following model
class Student
{
[Key]
public int Id { get; set; }
public string name{get;set;}
public string guid{get;set;}
}
and my table looks like this
id| name | guid
--------------
1 Andrew | C
2 John | D
3 Adam | B
4 Charles| A
5 Jacob | A
Now I would like to get the last two unique GUIDs which will be A and B.
and then I would like to get all row in which these GUIS appeared in the table. so I would like Jacob,Charles and Adam returned. Any suggestions on how I can get started with this ? I know Ill have to sortby then select unique. But I am not sure how Ill do it in Entity.
I think you could do something like this:
var result = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.SelectMany(s => s.Take(1));
1- Order by Id descending to get to the last Id's first.
2- Then group by the Guid and take the first 2 groups.
3- Select the top 1 for each group.
You need to only use this if you want output as Jacob,Charles and Adam
Original Credits #Stackberg use suggested query like without Take if the indented result.
//This work against in memory list (TESTED)
var result = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.SelectMany(s=>s.ToList());
//IF EF doesn't able to convert the query you can try this.
var inMemoryGrouped = dbcontext.Students.OrderByDescending(s => s.Id)
.GroupBy(s => s.Guid)
.Take(2)
.ToList();
//Flatten the items using select many
var final = inMemoryGrouped.SelectMany(y=>y.ToList());
Only thing it differ from #Stackberg answer is omitted the Take after grouping.

Linq to select highest ID where the ID is alphanumeric

I have a list of ID where the ID's start with MB (for members) or NM (for non members).
The ID would be like MB-101 or NM-108 etc...
I am trying to select the Highest ID starting with MB and then Add 1 and then save back to DB. Saving is easy but I am not sure how to query the highest Member or Nonmember ID and add one to it. Any help is much appreciated
You can do something like this:
List<string> list = new List<string>() { "MB-101", "MB-102", "MB-103", "MB-104"};
var ids = list.Select(x =>Convert.ToInt32(x.Replace("MB-", "")));//convert all the number parts to integer
list[list.FindIndex(x => x == "MB-" + ids.Max().ToString())] = "MB-" + (ids.Max() + 1);//set the max number after adding one.
You can do the same with your Nonmember ID. It is tested code, it successfully addresses your problem.
Hope it helps.
You can get the max id by splitting your list like below:
var ids = yourList.Where(x => x.ID.StartsWith("MB-")).Select(x => new { ID = x.ID.Split('-')[1] }).ToList();
var maxIdValue = ids.Select(x => int.Parse(x.ID)).ToList().Max();
If you want max id from both starting with MB- and NB- than you can remove above where condition. By this it will fetch max id from both MB- and NB-. Following will be query than:
var ids = yourList.Select(x => new { ID = x.ID.Split('-')[1] }).ToList();
var maxIdValue = ids.Select(x => int.Parse(x.ID)).ToList().Max();
you can try like this
List<string> lststr = new List<string>() { "MB-101", "MB-103", "MB-102", "NM-108" };
var result = "MB-"+ lststr
.Where(x=>x.Contains("MB"))
.Select(x => Regex.Replace(x, #"[^\d]", ""))
.OrderByDescending(x=>x)
.FirstOrDefault();
it will return MB-103 because it will first check if the string contains MB then it will replace everything with "" other than digit and OrderByDescending it will order by Descending so that the highest value will be on top and at last FirstOrDefault will get the fist value
You have to do OrderByDescending your list by replacing MB or NM with empty and get FirstOrDefault from ordered list. Please check below example.
CODE:
List<string> list = new List<string>() { "MB-101", "MB-102", "MB-109", "MB-105", "NM-110"};
var maxMember = list.OrderByDescending(m=>Convert.ToInt16(m.Replace("MB-","").Replace("NM-",""))).ToList().FirstOrDefault();
Console.WriteLine(maxMember.ToString());

C# List values compare and add

var bndlSummary = GetBundleSummary(GroupIds);
var cntrSummary = GetContainerSummary(GroupIds);
var finalSummary = GetFinalSummary(GroupIds);
Above var are fetching some data from Database. They all have one Common Field Name "City".
City value can be repeated many time like City = Chicago can be 3 times or more). now I want this Field City value into allCityNames. I don't want City Info to be repeated from any var.
var allCityNames = new cityAnalysisSummary();
Please help me how how should i do it. Thank you very much for your help.
bndlSummary.Select(b => b.City)
.Concat(cntrSummary.Select(c => c.City))
.Concat(finalSummary.Select(f => f.City))
.Distinct();
Use Select to get all the cities from each collection, Concat to put them all together, and Distinct to remove any duplicates.
You can also use Union which will remove duplicates while concatenating:
bndlSummary.Select(b => b.City)
.Union(cntrSummary.Select(c => c.City))
.Union(finalSummary.Select(f => f.City));

Duplicate values using linq

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

Categories

Resources