What is the alternate way of using LINQ ForEach loop? - c#

medicineList.ForEach(x =>
{
DoctorsOrderViewModel vm = new DoctorsOrderViewModel()
{
DrugID = x.PKID,
Name = x.Name,
DrugName = x.Name,
UnitName = x.UnitName,
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
DosageFormID = x.DosageFormID,
InventoryTypeID = x.InventoryTypeID,
};
temp.Add(vm);
this.DrugItemsComboForSearch.Add(vm);
DoctorsOrderViewModel vm2 = new DoctorsOrderViewModel() { CategoryID = x.CategoryID, CategoryName = x.CategoryName, };
if (!this.MedicineCategoryItemsCombo.Select(y => y.CategoryID).Contains(x.CategoryID))
{
this.MedicineCategoryItemsCombo.Add(vm2);
}
});
In my Case for 13000 Medicine this code took 8-10 sec to complete but its too lengthy considering performance issue. How can i optimized this?

What is the alternate way of using LINQ ForEach loop?
A standard foreach.
How can i optimized this
As to performance, its not yourForEach that's the problem, its probably the select and contains ,consider using a ToHashSet once
var set = this.MedicineCategoryItemsCombo.Select(y => y.CategoryID).ToHashSet();
Then you can use in your loop
if (set.Add(x.CategoryID))
{
this.MedicineCategoryItemsCombo.Add(vm2);
}
However on reading your code, this can probably be optimised with a better query and Where, then do a Select

Update: I got some time so I was able to write a complete example:
The results:
10x OPWay for 13000 medicines and 1000 categories: 00:00:03.8986663
10x MyWay for 13000 medicines and 1000 categories: 00:00:00.0879221
Summary
Use AddRange after a transformation with .Select
Use Distinct at the end of the process rather than scanning and adding one by one in each loop.
Solution
public static List<(string catId, string catName)> MyWay(List<Medicine> medicineList)
{
var temp = new List<DoctorsOrderViewModel>();
var DrugItemsComboForSearch = new List<DoctorsOrderViewModel>();
var transformed = medicineList.Select(x =>
{
return new DoctorsOrderViewModel()
{
DrugID = x.PKID,
Name = x.Name,
DrugName = x.Name,
UnitName = x.UnitName,
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
DosageFormID = x.DosageFormID,
InventoryTypeID = x.InventoryTypeID,
};
}).ToList(); ;
temp.AddRange(transformed);
DrugItemsComboForSearch.AddRange(transformed);
var MedicineCategoryItemsCombo = transformed.Select(m => (catId: m.CategoryID, catName: m.CategoryName)).Distinct().ToList();
return MedicineCategoryItemsCombo;
}
Full example:
public static class MainClass
{
public class Medicine
{
public string PKID { get; set; }
public string Name { get; set; }
public string UnitName { get; set; }
public string CategoryID { get; set; }
public string CategoryName { get; set; }
public string DosageFormID { get; set; }
public string InventoryTypeID { get; set; }
}
public class DoctorsOrderViewModel
{
public string DrugID { get; set; }
public string Name { get; set; }
public string DrugName { get; set; }
public string UnitName { get; set; }
public string CategoryID { get; set; }
public string CategoryName { get; set; }
public string DosageFormID { get; set; }
public string InventoryTypeID { get; set; }
}
class Category
{
public string CategoryID { get; set; }
}
public static void Main()
{
var medicines = new List<Medicine>();
medicines.AddRange(Enumerable.Range(0, 13000).Select(i => new Medicine()
{
PKID = "PKID" + i,
Name = "Name" + i,
UnitName = "UnitName" + i,
CategoryID = "CategoryID" + i%1000,
CategoryName = "CategoryName for CategoryID" + i%1000,
DosageFormID = "DosageFormID" + i,
InventoryTypeID = "InventoryTypeID" + i,
}));
Stopwatch sw = new Stopwatch();
sw.Start();
List<DoctorsOrderViewModel> comboData = null;
for (int i = 0; i < 10; i++)
{
comboData = OpWay(medicines);
}
var elapsed = sw.Elapsed;
Console.WriteLine($"10x OPWay for {medicines.Count} medicines and {comboData.Count} categories: {elapsed}");
sw.Restart();
List<(string catId, string catName)> comboData2 = null;
for (int i = 0; i < 10; i++)
{
comboData2 = MyWay(medicines);
}
elapsed = sw.Elapsed;
Console.WriteLine($"10x MyWay for {medicines.Count} medicines and {comboData2.Count} categories: {elapsed}");
}
public static List<DoctorsOrderViewModel> OpWay(List<Medicine> medicineList)
{
List<DoctorsOrderViewModel> MedicineCategoryItemsCombo = new List<DoctorsOrderViewModel>();
var temp = new List<DoctorsOrderViewModel>();
var DrugItemsComboForSearch = new List<DoctorsOrderViewModel>();
medicineList.ForEach(x =>
{
DoctorsOrderViewModel vm = new DoctorsOrderViewModel()
{
DrugID = x.PKID,
Name = x.Name,
DrugName = x.Name,
UnitName = x.UnitName,
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
DosageFormID = x.DosageFormID,
InventoryTypeID = x.InventoryTypeID,
};
temp.Add(vm);
DrugItemsComboForSearch.Add(vm);
DoctorsOrderViewModel vm2 = new DoctorsOrderViewModel() { CategoryID = x.CategoryID, CategoryName = x.CategoryName, };
if (!MedicineCategoryItemsCombo.Select(y => y.CategoryID).Contains(x.CategoryID))
{
MedicineCategoryItemsCombo.Add(vm2);
}
});
return MedicineCategoryItemsCombo;
}
public static List<(string catId, string catName)> MyWay(List<Medicine> medicineList)
{
var temp = new List<DoctorsOrderViewModel>();
var DrugItemsComboForSearch = new List<DoctorsOrderViewModel>();
var transformed = medicineList.Select(x =>
{
return new DoctorsOrderViewModel()
{
DrugID = x.PKID,
Name = x.Name,
DrugName = x.Name,
UnitName = x.UnitName,
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
DosageFormID = x.DosageFormID,
InventoryTypeID = x.InventoryTypeID,
};
}).ToList(); ;
temp.AddRange(transformed);
DrugItemsComboForSearch.AddRange(transformed);
var MedicineCategoryItemsCombo = transformed.Select(m => (catId: m.CategoryID, catName: m.CategoryName)).Distinct().ToList();
return MedicineCategoryItemsCombo;
}
}

You can use different approach for foreach, which is better than above, also code could be minimised a bit:
foreach (Medicine medicine in medicineList)
{
DoctorsOrderViewModel vm = new DoctorsOrderViewModel()
{
DrugID = x.PKID,
Name = x.Name,
DrugName = x.Name,
UnitName = x.UnitName,
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
DosageFormID = x.DosageFormID,
InventoryTypeID = x.InventoryTypeID,
};
temp.Add(vm);
this.DrugItemsComboForSearch.Add(vm);
if (!this.MedicineCategoryItemsCombo.Select(y => y.CategoryID ==
x.CategoryID).Any())
{
this.MedicineCategoryItemsCombo.Add(new DoctorsOrderViewModel()
{
CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
};);
}
}

Related

How to use linq to "flatten" an hierachy?

Given the following code example, how do I:
Get the commented out lines in the unfiltered list to work (without changing the definition of Result)?
Get the commented out lines in the filtered list to work (without changing the definition of Result)? From my maths it should give 32 records. Hopefully my output intent is clear enough for others to understand
Any questions feel free to ask
Regards
Kyle
//Populate data
var alphas = new List<Alpha>();
for (int a = 1; a <= 10; a++)
{
var alpha = new Alpha() { Id = a, Name = "A" + a };
for (int b = 1; b <= 10; b++)
{
var beta = new Beta() { Id = b, Name = "B" + b };
for (int c = 1; c <= 10; c++)
{
var charlie = new Charlie() { Id = c, Name = "C" + c };
for (int d = 1; d <= 10; d++)
{
var delta = new Delta() { Id = d, Name = "D" + d };
charlie.Deltas.Add(delta);
}
beta.Charlies.Add(charlie);
}
alpha.Betas.Add(beta);
}
alphas.Add(alpha);
}
//Get results into required format without filtering
var unfilteredResults = alphas.Select(a => new Result
{
AId = a.Id,
AName = a.Name,
//BId = a.Betas.Select(b => b.Id),
//BName = a.Betas.Select(b => b.Name),
//CId = a.Betas.Select(b => b.Charlies.Select(c => c.Id)),
//CName = a.Betas.Select(b => b.Charlies.Select(c => c.Name)),
//DId = a.Betas.Select(b => b.Charlies.Select(c => c.Deltas.Select(d => d.Id))),
//DName = a.Betas.Select(b => b.Charlies.Select(c => c.Deltas.Select(d => d.Name)))
});
var whiteListAIds = new List<int>() { 1, 2 };
var whiteListBIds = new List<int>() { 3, 4 };
var whiteListCIds = new List<int>() { 5, 6 };
var whiteListDIds = new List<int>() { 7, 8 };
//Get results into required format with filtering
var filteredResults = alphas.Where(a => whiteListAIds.Contains(a.Id)).Select(a => new Result
{
AId = a.Id,
AName = a.Name,
//BId = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Id),
//BName = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Name),
//CId = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Charlies.Where(c => whiteListCIds.Contains(c.Id)).Select(c => c.Id)),
//CName = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Charlies.Where(c => whiteListCIds.Contains(c.Id)).Select(c => c.Name)),
//DId = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Charlies.Where(c => whiteListCIds.Contains(c.Id)).Select(c => c.Deltas.Where(d => whiteListDIds.Contains(d.Id)).Select(d => d.Id))),
//DName = a.Betas.Where(b => whiteListBIds.Contains(b.Id)).Select(b => b.Charlies.Where(c => whiteListCIds.Contains(c.Id)).Select(c => c.Deltas.Where(d => whiteListDIds.Contains(d.Id)).Select(d => d.Name)))
});
class Alpha
{
public int Id { get; set; }
public string Name { get; set; }
public List<Beta> Betas { get; set; } = new List<Beta>();
}
class Beta
{
public int Id { get; set; }
public string Name { get; set; }
public List<Charlie> Charlies { get; set; } = new List<Charlie>();
}
class Charlie
{
public int Id { get; set; }
public string Name { get; set; }
public List<Delta> Deltas { get; set; } = new List<Delta>();
}
class Delta
{
public int Id { get; set; }
public string Name { get; set; }
}
class Result
{
public int AId { get; set; }
public string AName { get; set; }
public int BId { get; set; }
public string BName { get; set; }
public int CId { get; set; }
public string CName { get; set; }
public int DId { get; set; }
public string DName { get; set; }
}
Got it working as below thanks to the first answer linq selectmany flatten multiple levels
Basically had to combine .SelectMany() on the "outer" parents and .Select() on the last/inner child.
//Populate data
var alphas = new List<Alpha>();
for (int a = 1; a <= 10; a++)
{
var alpha = new Alpha() { Id = a, Name = "A" + a };
for (int b = 1; b <= 10; b++)
{
var beta = new Beta() { Id = b, Name = "B" + b };
for (int c = 1; c <= 10; c++)
{
var charlie = new Charlie() { Id = c, Name = "C" + c };
for (int d = 1; d <= 10; d++)
{
var delta = new Delta() { Id = d, Name = "D" + d };
charlie.Deltas.Add(delta);
}
beta.Charlies.Add(charlie);
}
alpha.Betas.Add(beta);
}
alphas.Add(alpha);
}
var unfilteredResults = alphas.SelectMany(a => a.Betas.SelectMany(b=> b.Charlies.SelectMany(c=> c.Deltas.Select(d => new Result
{
AId = a.Id,
AName = a.Name,
BId = b.Id,
BName = b.Name,
CId = c.Id,
CName = c.Name,
DId = d.Id,
DName = d.Name
}))));
var whiteListAIds = new List<int>() { 1, 2 };
var whiteListBIds = new List<int>() { 3, 4 };
var whiteListCIds = new List<int>() { 5, 6 };
var whiteListDIds = new List<int>() { 7, 8 };
//Get results into required format with filtering
var filteredResults = unfilteredResults.Where(r => whiteListAIds.Contains(r.AId) && whiteListBIds.Contains(r.BId) && whiteListCIds.Contains(r.CId) && whiteListDIds.Contains(r.DId));
Console.WriteLine("Finished");
class Alpha
{
public int Id { get; set; }
public string Name { get; set; }
public List<Beta> Betas { get; set; } = new List<Beta>();
}
class Beta
{
public int Id { get; set; }
public string Name { get; set; }
public List<Charlie> Charlies { get; set; } = new List<Charlie>();
}
class Charlie
{
public int Id { get; set; }
public string Name { get; set; }
public List<Delta> Deltas { get; set; } = new List<Delta>();
}
class Delta
{
public int Id { get; set; }
public string Name { get; set; }
}
class Result
{
public int AId { get; set; }
public string AName { get; set; }
public int BId { get; set; }
public string BName { get; set; }
public int CId { get; set; }
public string CName { get; set; }
public int DId { get; set; }
public string DName { get; set; }
}

Linq counting second grouping and counting without grouping

I'm trying to build a summary query that i will be using for statistics.
i have a dataTable with the folowing columns (approx 18000 rows) :
Artist / Album / file_path (one for each song) / rating /
each artist has 1 or several album with has songs and each songs have a rating
I want to have the following result :
For each artist ID (more reliable than the artist name), the total number of albums, the total number of songs, and the total number of ratings equal to 5.
Artist x / #album / #songs / #rating = 5 / song.first() //in song.first i have access to the file path, it can be any file path from the artist hence the first one.
I've been pulling my hair for several hours now and i cannot manage to get the # of albums per artist :( This is what i've been trying so far :
i have a Class for the query :
public class art_detail
{
public string artiste { get; set; }
public string fp { get; set; } // the file_path
public int nbr_album { get; set; }
public int nbr_song { get; set; }
public int nbr_rat5 { get; set; }
}
this is the query i came up to :
var result = from res in Globals.ds.Tables[0].AsEnumerable() // the table
.GroupBy(x => new { art = x.Field<int>("Artist_ID"), alb = x.Field<string>("album") })
.Select(x => new art_detail { artiste = x.Select(p =>p.Field<string>("artiste")).First(), fp = x.Select(p=>p.Field<string>("file_path")).First(), nbr_album = x.Key.alb.Count() })
.OrderBy(x => x.artiste)
select res;
The count is unfortunately completely wrong and i have no idea how to get the # of rating = 5 :(
Thanks for the help !
Edit :
Here is my query to make it work :
var table = Globals.ds.Tables[0].AsEnumerable();
var stats = table.GroupBy(x => x.Field<int>("Artist_ID"))
.Select(x => new art_detail
{
artiste = x.Select(p=>p.Field<string>("artiste")).First(),
nbr_album = x.Select(y => y.Field<string>("album")).Distinct().Count(),
fp = x.Select(y => y.Field<string>("file_path")).FirstOrDefault(),
nbr_song = x.Count(),
nbr_rat5 = x.Count(y => y.Field<int>("Rating") == 5)
});
Simpler than what i thought :)
Assuming a table whose schema matches this class:
public class Song
{
public string ArtistID { get; set; }
public string Album { get; set; }
public string FilePath { get; set; }
public int Rating { get; set; }
}
and given a LINQ source, you have the following query:
IQueryable<Song> table = /*insert source*/;
var stats = table.GroupBy(x => x.ArtistID);
.Select(x => new art_detail
{
artiste = x.Key,
nbr_album = x.Select(y => y.Album).Distinct().Count(),
nbr_song = x.Count(),
nbr_rat5 = x.Count(y => y.Rating == 5),
});
I used head compiled query as it seemed more understandable for me in this case:
Example model:
public class Artist
{
public string ArtistID { get; set; }
public string Album { get; set; }
public string FilePath { get; set; }
public int Rating { get; set; }
public int NumberOfSongs { get; set; }
}
Creating some dummy records for Usher and Beyonce:
//Usher
var artistOne = new Artist()
{
ArtistID = "Usher",
Album = "Lit",
FilePath = "dummy/path/here",
Rating = 5,
NumberOfSongs = 9
};
var artistTwo = new Artist()
{
ArtistID = "Usher",
Album = "Sick",
FilePath = "dummy/path/here",
Rating = 5,
NumberOfSongs = 11
};
var artistThree = new Artist()
{
ArtistID = "Usher",
Album = "Dope",
FilePath = "dummy/path/here",
Rating = 4,
NumberOfSongs = 14
};
//Beyonce
var artistFour = new Artist()
{
ArtistID = "Beyonce",
Album = "Hot",
FilePath = "dummy/path/here",
Rating = 5,
NumberOfSongs = 8
};
var artistFive = new Artist()
{
ArtistID = "Beyonce",
Album = "Fire",
FilePath = "dummy/path/here",
Rating = 4,
NumberOfSongs = 16
};
var listOfArtist = new List<Artist> { artistOne, artistTwo, artistThree, artistFour, artistFive };
Running query:
var result = from a in listOfArtist
where a.Rating == 5
group a by a.ArtistID into art
select new
{
artist = art.Key,
numberOfAlbums = art.Count(),
numberOfSongs = art.Sum(d => d.NumberOfSongs),
};
Results:
Hope this helps =)

Intersect 2 different kinds of collections based on string property of different name

I have a collection of 2 different kinds of objects.
I'm trying to do an .Intersect based on a string property......
public class EmployeeDto
{
public string SSN { get; set; }
public DateTime HireDate { get; set; }
}
public class PersonDto
{
public string SocialSecurityNumber { get; set; }
public string Name { get; set; }
}
Attempts:
ICollection<EmployeeDto> empsColl = new List<EmployeeDto>();
empsColl.Add(new EmployeeDto() { SSN = "222-22-2222", HireDate = DateTime.Now });
empsColl.Add(new EmployeeDto() { SSN = "333-33-3333", HireDate = DateTime.Now });
empsColl.Add(new EmployeeDto() { SSN = "444-44-4444", HireDate = DateTime.Now });
empsColl.Add(new EmployeeDto() { SSN = "555-55-5555", HireDate = DateTime.Now });
ICollection<PersonDto> pers = new List<PersonDto>();
pers.Add(new PersonDto() { SocialSecurityNumber = "333-33-3333", Name = "John" });
pers.Add(new PersonDto() { SocialSecurityNumber = "444-44-4444", Name = "Mary" });
ICollection<EmployeeDto> overlap1 = empsColl.Where(api => api.SSN.Any(val => val.Equals(pers.Any(cl => cl.SocialSecurityNumber.Equals(val))))).ToList();
ICollection<EmployeeDto> overlap2 = empsColl.Where(api => api.SSN.Equals(pers.Any(per => per.SocialSecurityNumber.Equals(api.SSN, StringComparison.OrdinalIgnoreCase)))).ToList();
foreach (EmployeeDto emp in overlap1)
{
Console.WriteLine(emp.SSN);
}
The desired result is a ICollection<EmployeeDto> that contains the EmployeeDto objects of 333-33-3333 and 444-44-4444 of course.
Thanks.
Here is how it can be done:
var overlap = empsColl.Where(e => pets.Any(p => p.SocialSecurityNumber == e.SSN)).ToList();
I think this would do it
empsColl.Where(ec => pers.Select(p => p.SocialSecurityNumber).Contains(ec.SSN)));
This should work
var result = empsColl.Where(x => pers.Any(y=> string.Compare(y.SocialSecurityNumber, x.SSN) == 0));

How can I create set contain id record in first set equal id record in second set?

In database I have two tables:
public partial class PersonOne
{
public int id { get; set; }
public string name { get; set; }
public string surname { get; set; }
}
public partial class PersonTwo
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
}
I would like to fill my set:
public class PersonOnePersonTwo
{
public int PersonOneId { get; set; }
public int PersonTwoId { get; set; }
}
where PersonOne.name == PersonTwo.firstname && PersonOne.surname == PersonTwo.lastname but I have no idea how I can do that - because below code isn't efficient and is so slow:
List<PersonOne> personOneList = new List<PersonOne>();
List<PersonTwo> personTwoList = new List<PersonTwo>();
List<PersonOnePersonTwo> personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (PersonOne personOne in personOneList)
{
foreach(PersonTwo personTwo in personTwoList.Where(x => x.firstname == personOne.name && x.lastname == personOne.surname).ToList())
{
personOnePersonTwoList.Add(new PersonOnePersonTwo
{
PersonOneId = personOne.id,
PersonTwoId = personTwo.id
});
}
};
Try this:
var result = personOneList.Join
(
personTwoList,
person1 => new { Key1 = person1.Name, Key2 = person1.Surname },
person2 => new { Key1 = person2.FirstName, Key2 = person2.LastName },
(person1, person2) => new PersonOnePersonTwo { PersonOneId = person1.Id, PersonTwoId = person2.Id }
).ToList();
I would go with:
var personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (var personOne in personOneList)
{
personOnePersonTwoList = personTwoList.Where(x => x.firstname.Equals(personOne.name, StringComparison.OrdinalIgnoreCase) &&
x.lastname.Equals(personOne.surname, StringComparison.OrdinalIgnoreCase))
.Select(x => new PersonOnePersonTwo {PersonOneId = personOne.id, PersonTwoId = x.id}).ToList();
};
As a side note: it's more convinient to use Equals when comparing strings.

Linq : Comparing 1 Child Collection to (Aggregated) ChildCollection(s)

I have a Linq question: (DotNet Framework 4.0)
I have the following classes:
public class Employee
{
public Guid? EmployeeUUID { get; set; }
public string SSN { get; set; }
}
public class JobTitle
{
public Guid? JobTitleSurrogateKey { get; set; }
public string JobTitleName { get; set; }
}
public class EmployeeToJobTitleMatchLink
{
public EmployeeToJobTitleMatchLink()
{
this.TheJobTitle = new JobTitle() { JobTitleSurrogateKey = Guid.NewGuid(), JobTitleName = "SomeJobTitle:" + Guid.NewGuid().ToString("N") };
}
public Guid LinkSurrogateKey { get; set; }
/* Related Objects */
public Employee TheEmployee { get; set; }
public JobTitle TheJobTitle { get; set; }
}
public class Organization
{
public Organization()
{
this.Links = new List<EmployeeToJobTitleMatchLink>();
}
public int OrganizationSurrogateKey { get; set; }
public ICollection<EmployeeToJobTitleMatchLink> Links { get; set; }
}
In my code below, I can compare 2 child-collections and get the results I need (in "matches1".
Here I am using the "SSN" string property to compare and find the overlaps. And the Console.Write for matches1 works as I expect.
What I don't know how to do is compare the first child collection (org10) to all the children in (allOtherOrgsExceptOrg10 (all the Organizations and all the Links of these Organizations )
The commented out code shows kinda what I'm trying to do, one of my many feeble attempts today.
But basically, match2 would be populated with all the SSN overlaps...but comparing org10 with allOtherOrgsExceptOrg10, all their "Links", and their Employee.SSN's.
org10 overlaps with org20 with "AAA", so match2 would contain "AAA". and org10 overlaps with org30 with "BBB" so match2 would contain "BBB".
Organization org10 = new Organization();
org10.OrganizationSurrogateKey = 10;
Employee e11 = new Employee() { SSN = "AAA", EmployeeUUID = new Guid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA") };
EmployeeToJobTitleMatchLink link11 = new EmployeeToJobTitleMatchLink();
link11.TheEmployee = e11;
org10.Links.Add(link11);
Employee e12 = new Employee() { SSN = "BBB", EmployeeUUID = new Guid("BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB") };
EmployeeToJobTitleMatchLink link12 = new EmployeeToJobTitleMatchLink();
link12.TheEmployee = e12;
org10.Links.Add(link12);
Organization org20 = new Organization();
org20.OrganizationSurrogateKey = 20;
Employee e21 = new Employee() { SSN = "AAA", EmployeeUUID = new Guid("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA") };
EmployeeToJobTitleMatchLink link21 = new EmployeeToJobTitleMatchLink();
link21.TheEmployee = e21;
org20.Links.Add(link21);
Employee e22 = new Employee() { SSN = "CCC", EmployeeUUID = new Guid("CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC") };
EmployeeToJobTitleMatchLink link22 = new EmployeeToJobTitleMatchLink();
link22.TheEmployee = e22;
org20.Links.Add(link22);
Organization org30 = new Organization();
org30.OrganizationSurrogateKey = 30;
Employee e31 = new Employee() { SSN = "BBB", EmployeeUUID = new Guid("BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB") };
EmployeeToJobTitleMatchLink link31 = new EmployeeToJobTitleMatchLink();
link31.TheEmployee = e31;
org30.Links.Add(link31);
Employee e32 = new Employee();
e32.SSN = "ZZZ";
EmployeeToJobTitleMatchLink link32 = new EmployeeToJobTitleMatchLink();
link32.TheEmployee = e32;
org30.Links.Add(link32);
IList<Organization> allOtherOrgsExceptOrg10 = new List<Organization>();
/* Note, I did not add org10 here */
allOtherOrgsExceptOrg10.Add(org20);
allOtherOrgsExceptOrg10.Add(org30);
IEnumerable<EmployeeToJobTitleMatchLink> matches1 =
org10.Links.Where(org10Link => org20.Links.Any(org20Link => org20Link.TheEmployee.SSN.Equals(org10Link.TheEmployee.SSN, StringComparison.OrdinalIgnoreCase)));
IEnumerable<EmployeeToJobTitleMatchLink> matches2 = null;
//org10.Links.Where(org10Link => ( allOtherOrgs.Where ( anyOtherOrg => anyOtherOrg.Links.Any(dbSideChild => dbSideChild.TheEmployee.SSN == org10Link.TheEmployee.SSN)) );
if (null != matches1)
{
foreach (EmployeeToJobTitleMatchLink link in matches1)
{
Console.WriteLine(string.Format("matches1, SSN = {0}", link.TheEmployee.SSN));
}
}
if (null != matches2)
{
foreach (EmployeeToJobTitleMatchLink link in matches2)
{
Console.WriteLine(string.Format("matches2, SSN = {0}", link.TheEmployee.SSN));
}
}
matches2 =
allOtherOrgsExceptOrg10.SelectMany(x => x.Links)
.Where(x => org10.Links.Select(o => o.TheEmployee.SSN).Contains(x.TheEmployee.SSN));
You can use the SelectMany on the allOther collection to select all Links over all org's. Then check if any SSN is inside the org10 List.
See: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany(v=vs.100).aspx
You can use SelectMany to flatten out the collection and then use it just like you have for matches1
IEnumerable<EmployeeToJobTitleMatchLink> matches2 =
org10.Links.Where(
org10Link =>
allOtherOrgsExceptOrg10.SelectMany(allOtherOrgs => allOtherOrgs.Links).Any(
anyOtherLink =>
anyOtherLink.TheEmployee.SSN.Equals(org10Link.TheEmployee.SSN, StringComparison.OrdinalIgnoreCase)));
The SelectMany will make it seem like one IEnumerable instead of and IEnumerable of an IEnumerable.

Categories

Resources