Reputation: 163
class Officer
{
Person person;
}
class Person
{
string name;
}
Suppose I've a list of Officer and a list of Person. I want to filter these two list based on some criteria.
So I wrote this method:
public List<Person> filterName(List<Person> list)
{
// some filter logic
}
And I'm using this method for the two lists in the following way:
main()
{
...
List<Officer> officers = Initialize();
List<Person> validNames= filterNames(officers.Select(o=>o.person.name).ToList())
foreach (var officer in officers)
{
if (!validNames.Contains(officer.Person.name))
officers.remove(officer);
}
// finally I have a valid set of officers here
List<Person> persons = Initialize();
var filteredPersons = filterNames(persons.Select(o=>o.name).ToList())
}
Is there a good way to use generics so I can avoid the following code in the main method()?
List<string> validNames = filterNames(officers.Select(o=>o.fullName).ToList())
foreach (var officer in officers)
{
if (!validNames.Contains(officer.name))
officers.remove(officer);
}
And use generics somehow to update the officers list using generics.
Upvotes: 1
Views: 1428
Reputation: 11273
Ok, let's assume you have some complicated FilterNames
function that operates on a list, and your goal is to filter out based on some Person
criteria. I would rewrite the filter like this:
public bool FilterPerson(Person p)
{
//Some complicated logic
//Returns true if person should be kept
//Returns false if the person should be rejected
}
Now you can use that in a Linq statement:
var officers = Initialize().Where(o => FilterPerson(o.Person)).ToList();
No need to remove items from the list. You could still use the interim object, it just requires an additional step:
var officers = Initialize(); //Returns List<Officer>
var filteredOfficers = officers.Where(o => FilterPerson(o.Person)).ToList();
Upvotes: 2
Reputation: 8693
New answer based on recent edits:
var officers = new List<Officer>
{
new Officer { Name = "Officer Foo" },
new Officer { Name = "Officer Bar" }
};
officers.RemoveAll(o => o.Name.Contains("Bar"));
// Officers now only contains "Officer Foo"
------------ Old answer here ----------------
Can you use OOP here and derive Person
and Officer
from something in common?
If so, then you can easily take their common property and filter on that instead of writing two separate pieces of logic to deal with each of them.
static void Main(string[] args)
{
var officers = new List<Officer>
{
new Officer { Name = "Officer Foo" },
new Officer { Name = "Officer Bar" }
};
var workers = new List<Worker>
{
new Worker { Name = "Worker Foo" },
new Worker { Name = "Worker Bar" }
};
var people = workers.Cast<IPerson>().Concat(officers);
var filteredPeople = Program.Filter(people, "Foo");
Console.ReadKey(true);
}
static IEnumerable<IPerson> Filter(IEnumerable<IPerson> people, string keyword)
{
return people.Where(p => p.Name.Contains(keyword));
}
interface IPerson
{
string Name { get; set; }
}
class Officer : IPerson
{
public string Name { get; set; }
}
class Worker : IPerson
{
public string Name { get; set; }
}
Upvotes: 3