comparing two list of strings in C# - c#

There are Candidate and Job entities:
public class Candidate
{
public int CandidateId { get; set; }
public string Name { get; set; }
public string SkillTags { get; set; }
public List<string> skillTagsList
{
get
{
return Array.ConvertAll(SkillTags.Split(','), p => p.Trim()).ToList();
}
}
}
public class Job
{
public int JobId { get; set; }
public string Name { get; set; }
public string Company { get; set; }
public string Skills { get; set; }
public List<string> skillsList
{
get
{
return Array.ConvertAll(Skills.Split(','), p => p.Trim()).ToList();
}
}
}
For each job, I want to get the candidates with most matching skills.
This LINQ query returns an error. is there a better LINQ query to get the results?
List<Candidate> candidates = repository.GetCandidates().Result;
List<Job> jobs = repository.GetJobs().Result;
List<Candidate> JobCandidates = null;
jobs.ForEach(j =>
{
JobCandidates = candidates.Where(c => c.skillTagsList.Any(st => j.skillsList.Contains(st.ToLower())));
}

For each job project (.Select) a new object containing the job and the candidate with the top number of matching skills (OrderDescendingBy the number of intersections):
var result = jobs.Select(j => new {
Job = j,
Candidate = candidates.OrderByDescending(c => c.skillTagsList.Intersect(j.skillsList).Count())
.First()
});

Related

Convert DataTable to a nested object using LINQ

I have a stored proc returning a datatable using a stored procedure. I am able to convert the it to an object using the following code
outgoingPaymentData.AsEnumerable().Select(x => new OutgoingPaymentApprovalDetails() { });
Here is my OutgoingPaymentApprovalDetails class
public class OutgoingPaymentApprovalDetails
{
public int OriginatorId { get; set; }
public string Name { get; set; }
public string DocumentId { get; set; }
public string DebtorName { get; set; }
public string Currency { get; set; }
public double Amount { get; set; }
public string Description { get; set; }
public string DebitAccountNo { get; set; }
public string CreditAccountNo { get; set; }
}
Now, instead of a flat list, I need to add heirarchy, to select this one object to 3 objects.
Classes as under:
public class OriginatorDetails
{
public int OriginatorId { get; set; }
public string Name { get; set; }
public List<DocumentDetails> DocumentDetails { get; set; }
}
public class DocumentDetails
{
public string DocumentId { get; set; }
public List<TransactionDetails> TransactionDetails { get; set; }
}
public class TransactionDetails
{
public string Amount { get; set; }
public string DebitAccountNo { get; set; }
public string CreditAccountNo { get; set; }
}
Basically, All Documents of a particular Originator have to be in the list of DocumentDetails and all TransactionDetails of a particular document have to be in that list.
One way is to create a dictionary and add stuff in it and finally create an object. I was wondering if there was a more abbreviated and efficient way to do something like this.
TIA
You can do the grouping of retrieved records of OutgoingPaymentApprovalDetails using Linq to create the nested object of OriginatorDetails collection.
see below code
var originalDetails = inputs.GroupBy(g => g.OriginatorId)
.Select(g => new OriginatorDetails()
{
OriginatorId = g.Key,
Name = g.First().Name,
DocumentDetails = g.GroupBy(d => d.DocumentId)
.Select(d => new DocumentDetails()
{
DocumentId = d.Key,
TransactionDetails = d.Select(t => new TransactionDetails()
{
DebitAccountNo = t.DebitAccountNo,
CreditAccountNo = t.CreditAccountNo,
Amount = t.Amount.ToString()
}).ToList()
})
.ToList()
});
Check the created https://dotnetfiddle.net/FCA7Qc to demostrate your scenario.
Try this code:
Basically you need to group 2 times, first time by OriginatorId and Name and then by DocumentId like this:
var result = list.GroupBy(c => new {c.OriginatorId, c.Name})
.Select(g => new OriginatorDetails()
{
Name = g.Key.Name,
OriginatorId = g.Key.OriginatorId,
DocumentDetails = g
.GroupBy(dd => dd.DocumentId)
.Select(dd => new DocumentDetails()
{
DocumentId = dd.Key,
TransactionDetails = dd.ToList()
.Select(td => new TransactionDetails()
{
Amount = td.Amount.ToString(),
CreditAccountNo = td.CreditAccountNo,
DebitAccountNo = td.DebitAccountNo
}).ToList()
}).ToList()
}).ToList();

NEST: Find Best match using elastic search

I am trying to write a query to find the best match. I have an index with the structure below.
public class UserProfileSearch
{
public int Id { get; set; }
public int Sex { get; set; }
public int Age { get; set; }
public int MaritalStatus { get; set; }
public int CountryLivingIn { get; set; }
public double Height { get; set; }
public double BodyWeight { get; set; }
...
}
When I start my search I use different parameters. I get the search parameters as an object which has the structure below.
public class UserPreference
{
public int Id { get; set; }
public int FromAge { get; set; }
public int ToAge { get; set; }
public int FromHeight { get; set; }
public int ToHeight { get; set; }
public string MartialStatus { get; set; } // This will have id in comma separated form: 11,23,24..
public string CountriesLivingIn { get; set; } // This will also have id in comma separated form: 11,23,24..
public string Sexes { get; set; }
...
}
I am trying to achieve like below.
QueryContainer qCs = null;
userPartnerPreference.CountriesLivingIn.Split(",").ToList().ForEach(id =>
{
qCs |= new TermQuery { Field = "countryLivingIn ", Value = int.Parse(id) };
});
QueryContainer qSs = null;
userPartnerPreference.MartialStatus.Split(",").ToList().ForEach(id =>
{
qSs &= new TermQuery { Field = "maritalStatus", Value = int.Parse(id) };
});
var searchResults = await _elasticClient.SearchAsync<UserProfileSearch>(s => s
.Query(q => q
.Bool(b => b
.Must(qSs)
.Should(
bs => bs.Range(r => r.Field(f => f.Age).GreaterThanOrEquals(userPartnerPreference.FromAge).LessThan(userPartnerPreference.ToAge)),
bs => bs.Range(r => r.Field(f => f.Height).GreaterThanOrEquals(userPartnerPreference.FromHeight).LessThanOrEquals(userPartnerPreference.ToHeight)),
bs => bs.Bool(bsb=>bsb.Should(qCs))
)
)
)
);
I basically want to find the best match result based on the parameters passed ordered by highest number of fields matched. I'm new to elastic search so is this the way to do it?
Note: I have other fields that I need to match. There are around 15 field, which I am planning to have inside should like age and height.

How can change a MYSQL Join Query in Linq Methods

I write a MySql join code, and want to retrive same value from the Dotnetcore linq methods.
My Join code is below:
SELECT GL.Id AS GradeLevels,
CRS.Name AS CourseName,
GL.Title AS GradlevelName,
AVG (ASTSTU.ObtainedMarks)
FROM GradeLevels GL
INNER JOIN Courses AS CRS ON CRS.GradeLevelsID = GL.Id
INNER JOIN Units AS UNT ON UNT.CourseID = CRS.ID
INNER JOIN Lessons AS LSN ON LSN.UnitsId = UNT.Id
INNER JOIN Assignments AS AST ON AST.LessonId = LSN.id
INNER JOIN AssignmentStudents AS ASTSTU ON ASTSTU.AssignmentId = AST.id
WHERE CRS.SchoolSystemsID = "08d6a1f2-26df-4ad5-25d3-2a26960aa3fd" -- School System id.
GROUP BY GL.Id;
Now I want to change above MySQL Join into Dotnet core linq method to create an API that will be Showing, I try to write code for this
public async Task<ICollection<GradeLevels>> GetSchoolSystemGradLevelsAverage(Guid schoolSystemId)
{
List<GradeLevels> dashboadOverAllAverage = new List<GradeLevels>();
var dashboadOverAllAverage1 = await _GpsContext.GradeLevels
.Include(d=>d.Departments)
.ThenInclude(c=>c.Courses.Where(s=>s.SchoolSystemsID ==schoolSystemId))
.ThenInclude(u=>u.Units)
.ThenInclude(l=>l.Lessons)
.ThenInclude(a=>a.Assignment)
.ThenInclude(a=>a.assignmentStudents)
.GroupBy(g=>g.ID)
.ToListAsync();
return dashboadOverAllAverage;
}
Now I want to show the data though API and want to call to fields GradeLvels name and Average Marks.
[HttpGet()]
public async Task<IActionResult> GetCEOGradeLevelAverage(string schoolSystemId)
{
var overallgradeAverages = await _ceoDashboadRepository.GetSchoolSystemGradLevelsAverage(Guid.Parse(schoolSystemId));
List<GetGradeLevelAverageVm> getOverallAverageVms = new List<GetGradeLevelAverageVm>();
foreach (GradeLevels overallgradeAverage in overallgradeAverages)
{
getOverallAverageVms.Add(new GetGradeLevelAverageVm
{
Marks = overallgradeAverage.Id.ToString(), //Want to show lable of AvrageMark
Name = overallgradeAverage.Name //Want to show Gradelevel name
});
}
return Ok(getOverallAverageVms);
}
You do select too much from your DB. Here an example, how to select the nessecary values:
using (TestDbContext ctx = new TestDbContext())
{
var tmp = ctx.AssignmentStudents
.Include(s => s.Assignment) // Include all Childs..
.ThenInclude(a => a.Lesson)
.ThenInclude(l => l.Unit)
.ThenInclude(u => u.Course)
.ThenInclude(c => c.GradeLevel)
.Where(a => a.LessonId == 123)
.GroupBy(g => // Group by your Key-Values Grade and Course (You could take names instead of ids. Just for simplification)
new
{
GradeLevel = g.Assignment.Lesson.Unit.Course.GradeLevel.Id,
Course = g.Assignment.Lesson.Unit.Course.Id
})
.Select(s => // Select the result into an anonymous type
new
{
GradeLevels = s.Key.GradeLevel, // with same keys like grouping
Course = s.Key.Course,
AverageObtainedMarks = s.Average(a => a.ObtainedMarks) // and an average ObtainedMarks from objects matching the key
})
.Where(s => s.GradeLevel == 1);
foreach (var t in tmp)
{
Console.WriteLine(t.GradeLevels + " " + t.Course + ": " + t.AverageObtainedMarks);
}
}
Here a the classes and dbcontext I used:
public class GradeLevel
{
public int Id { get; set; }
public List<Course> Courses { get; set; }
}
public class Course
{
public int Id { get; set; }
public int GradeLevelId { get; set; }
public GradeLevel GradeLevel { get; set; }
public List<Unit> Units { get; set; }
}
public class Unit
{
public int Id { get; set; }
public int CourseId { get; set; }
public Course Course { get; set; }
public List<Lesson> Lessons { get; set; }
}
public class Lesson
{
public int Id { get; set; }
public int UnitId { get; set; }
public Unit Unit { get; set; }
public List<Assignment> Assignments { get; set; }
}
public class Assignment
{
public int Id { get; set; }
public int LessonId { get; set; }
public Lesson Lesson { get; set; }
public List<AssignmentStudent> AssignmentStudents { get; set; }
}
public class AssignmentStudent
{
public int Id { get; set; }
public int AssignmentId { get; set; }
public Assignment Assignment { get; set; }
public decimal ObtainedMarks { get; set; }
}
public class TestDbContext : DbContext
{
public DbSet<AssignmentStudent> AssignmentStudents { get; set; }
public DbSet<Assignment> Assignments { get; set; }
public DbSet<Lesson> Lessons { get; set; }
public DbSet<Unit> Units { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<GradeLevel> GradeLevels { get; set; }
}

Filtering LINQ child collection EF

Im having some problems trying to do this filtering and im sure it can be done better than what im doing. I will show my classes and how im solving it but i was wondering if I could use Linq to filter this. My Classes:
public class Section
{
public int Id { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public virtual List<FeatureType> Features { get; set; }
}
public class ItemType
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<FeatureType> FeatureTypes { get; set; }
public override string ToString()
{
return Name;
}
}
public class FeatureType
{
public int Id { get; set; }
public string Name { get; set; }
public Section Section { get; set; }
public virtual List<ItemType> ItemTypes { set; get; }
}
I'm trying to get all Sections, and filter Features by an ItemTypeID, so only the FeatureTypes of that ItemTypes are listed. What Im doing now its just getting all sections, and just do a for and just add the ones that work for me in other:
public ItemTypeFeatureViewModel(int myItemTypeId, IUnitOfWork myUnitOfWork)
{
ItemTypeId = myItemTypeId;
unitOfWork = myUnitOfWork;
Sections = unitOfWork.SectionRepository.Get(includeProperties: "Features")
.ToList();
foreach (var item in Sections)
{
var x = new List<FeatureType>();
foreach (var feature in item.Features)
{
foreach (var itemType in feature.ItemTypes)
{
if (itemType.Id == ItemTypeId)
{
x.Add(feature);
break;
}
}
}
item.Features = x;
}
}
Can i improve this and avoid all this foreach?
You can't filter out included collection on server side, but you can replace two inner loops with:
item.Features = item.Features
.Where(f => f.ItemTypes.Any(i => i.Id == ItemTypeId))
.ToList();
That will select only those features which have at least one item type with id you provided.
Try the following:
Sections
.ForEach(x => x.Features = x.Features.Where(y => y.Any(z => z.Id == ItemTypeId))
.ToList());

RavenDb - Multimap index with filtered group by results

I have a requirement where I need to get a list of Races ordered by the race date. But I also need to add the races that were run by my friends to the top. So I am trying to maintain an index that will keep a count of my friends that have run each race.
I have the following objects:
public class Race {
public string Id { get; set; }
public string Name { get; set; }
public string Distance { get; set; }
public DateTime DateOfEvent { get; set; }
public string Location { get; set; }
}
public class Runner {
public string Id { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public string Hometown { get; set; }
public List<string> Friends { get; set; }
public List<string> RacesRun { get; set; }
}
And this is what I have for the index so far:
public class RacesByFriends : AbstractMultiMapIndexCreationTask<RacesByFriends.ReduceResult> {
public class ReduceResult {
public string RunnerId { get; set; }
public string RaceId { get; set; }
public int Count { get; set; }
}
public RacesByFriends() {
AddMap<Runner>(runners => from runner in runners
from race in runner.RacesRun
select new {
RunnerId = runner.Id,
RaceId = race,
Count = 1,
});
AddMap<Race>(races => from race in races
select new {
RunnerId = (string)null,
RaceId = race.Id,
Count = 0,
});
Reduce = results => from result in results
group result by new {
result.RunnerId,
result.RaceId
} into g
select new {
RunnerId = g.Select(x => x.RunnerId).FirstOrDefault(),
RaceId = g.Select(x => x.RaceId).FirstOrDefault(),
Count = g.Sum(x => x.Count)
};
}
}
My Question is, how do I get the the Count in ReduceResult to reflect only people that ran that race that exist in that runners friends list.
I ended up taking this down a different path. Oren stated that you can not filter the source data, and that made sense. Now, I simply index who ran what race and apply a where in filter at the query, then get all the races sorted in date order and remove the ones from the previous query.

Categories

Resources