Reputation: 65
I'm stuck at the following Problem: I want to load one List, but I can pass more than one Parameter what could be the criteria to find the Lists I want. Now I have the following structure:
House{
Name;
ID;
Alias;
}
Also I Have:
Person{
Name;
Alias;
}
This means, 1 house can hold multiple persons and multiple persons with the same name can be in multiple houses. So now I want to call my Function e.G. "GetHouses(string criteria)" as criteria could be:
Now I just read every house and it's data and I select afterwards by the criteria.
IMPORTANT NOTE: I can not change the logic until here!
So now as I try to find the matching criteria I came up with using LINQ as it is very fast. It works as long as I don't compare to the Persons:
result = (from x in result
where (
(string.Equals(x.Name, criteria))
|| (string.Equals(x.ID, criteria))
|| (x.Name.Contains(criteria))
select x).ToList();
Now I want to load every Person to the houses I found and check if a Name of the Persons in the house would match the criteria. Is there a way to do this within the LINQ I have already? Or do I have to go though the result with:
result.ForEach(x => ...)
Would be nice if it would work with the LINQ. I did a similar Logic with the
result.FindAll(new Predicate<House>((x) => { ... LoadPersons(criteria) {... } }));
But that took to long.
Kind regards, Asat0r
Upvotes: 0
Views: 1296
Reputation: 804
Here is a simple solution using three classes: Program
, House
and Person
.
The class House
"houses" (pun intended) a list of the class Person
(and your own values: name, id and alias). In this way the residents are a part of the house and not stored somewhere else. Storing the residents outside the House
class is the same as having your lunchbox's contents outside the box in your backpack.
The class Person
stores the basic information about the house's residents. Having a list of residents inside the House
class makes it easier to compare the search criteria with the people.
In the class Program
you'll find the Main
and the FindHouses
classes. These kinda explains themselves
class Person
{
public string name;
public string alias;
public Person(string _name, string _alias = "")
{
name = _name;
alias = _alias;
}
}
class House
{
public string name;
public string id;
public string alias;
public List<Person> people = new List<Person>();
public House(string _name, string _id, string _alias = "")
{
name = _name;
id = _id;
alias = _alias;
}
}
class Program
{
static List<House> houses = new List<House>();
static void Main(string[] args)
{
// Add houses here
foreach (House house in FindHouses("criteria"))
{
// Do stuff
}
}
// Find all the houses in which the criteria exists
static List<House> FindHouses(string criteria)
{
// Return the list of all houses in which the criteria exists
return houses.Where(h =>
h.name.Contains(criteria) ||
h.id == criteria ||
h.alias.Contains(criteria) ||
h.people.Any(p =>
p.name.Contains(criteria) ||
p.alias.Contains(criteria))).ToList();
}
}
I dont know if this is too big of a change in your code, but anyways, I hope this helps.
I know you mentioned you didn't want to load the persons into the houses, but this makes the search for houses based on "all values" much easier
Upvotes: 0
Reputation: 460380
Presuming that you have a PersonList
in your House
-class you could use Enumerable.Any
:
var matchingHouses = from house in allHouses
where string.Equals(house.Name, criteria)
|| string.Equals(house.ID, criteria)
|| house.Name.Contains(criteria)
|| house.PersonList.Any(resident => string.Equals(resident.Name, criteria))
select house;
If you have a method to return the "residents" you can use this. If you later want to access these persons you could create an anonymous type to store them:
var housesAndResidents = from house in allHouses
let matchingResidentList = LoadPersons(house.ID)
.Where(resident => string.Equals(resident.Name, criteria))
.ToList()
where string.Equals(house.Name, criteria)
|| string.Equals(house.ID, criteria)
|| house.Name.Contains(criteria)
|| matchingResidentList.Any()
select new { house, matchingResidentList };
You can access these properties in the following way:
var matchingHouseList = housesAndResidents.ToList();
// you don't need the list, you can use foreach directly,
// but whenever you access housesAndResidents you will execute that query
// ToList materializes this query into a collection, so you can enumerate it or use the Count property
foreach(var x in matchingHouseList )
{
Console.WriteLine("House:{0} Matching-Resident(s):{1}"
, x.house.Name
, String.Join(", ", x.matchingResidentList.Select(r => r.Name)));
}
Upvotes: 1