Reputation: 721
There is a list of persons and search object. Search object is to do search on main list.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DOB { get; set; }
public int Zip { get; set; }
public string OtherDetails { get; set; }
}
public class SearchParam
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? DOB { get; set; }
}
I am using SearchParam
object to search on List<Person>
.
My search function looks like this:
List<Person> GetResult(SearchParam search, List<Person> persons)
{
if (search == null && persons == null)
{
if (!string.IsNullOrWhiteSpace(search.FirstName)
&& string.IsNullOrWhiteSpace(search.LastName)
&& !search.DOB.HasValue
)
{
return persons.Where(p => p.FirstName.ToUpper().StartsWith(search.FirstName.ToUpper())).ToList();
}
if (string.IsNullOrWhiteSpace(search.FirstName)
&& !string.IsNullOrWhiteSpace(search.LastName)
&& !search.DOB.HasValue
)
{
return persons.Where(p => p.LastName.ToUpper().StartsWith(search.LastName.ToUpper())).ToList();
}
if (string.IsNullOrWhiteSpace(search.FirstName)
&& string.IsNullOrWhiteSpace(search.LastName)
&& search.DOB.HasValue
)
{
return persons.Where(p => p.DOB.Equals(search.DOB)).ToList();
}
if (!string.IsNullOrWhiteSpace(search.FirstName)
&& !string.IsNullOrWhiteSpace(search.LastName)
&& !search.DOB.HasValue
)
{
return persons.Where(p => p.FirstName.ToUpper().StartsWith(search.FirstName.ToUpper())
&& p.LastName.ToUpper().StartsWith(search.LastName.ToUpper())).ToList();
}
if (!string.IsNullOrWhiteSpace(search.FirstName)
&& !string.IsNullOrWhiteSpace(search.LastName)
&& search.DOB.HasValue
)
{
return persons.Where(p => p.FirstName.ToUpper().StartsWith(search.FirstName.ToUpper())
&& p.LastName.ToUpper().StartsWith(search.LastName.ToUpper())
&& p.DOB.Equals(search.DOB)).ToList();
}
return persons;
}
else
{
return persons;
}
}
This code "GetResult" is working but I am not satisfied with this it. How should I handle null values in the list and in search object and minimize the lines of code in this methods?
Upvotes: 0
Views: 89
Reputation: 1720
You can minimize if-else
clauses and nested blocks with code like this:
public static List<Person> GetResult(SearchParam search, List<Person> persons)
{
if (search == null || persons == null)
{
return persons;
}
var ignoreCase = StringComparison.CurrentCultureIgnoreCase;
var firstNamePrefix = string.IsNullOrWhiteSpace(search.FirstName) ? "" : search.FirstName;
var lastNamePrefix = string.IsNullOrWhiteSpace(search.LastName) ? "" : search.LastName;
return persons.Where(p => p.FirstName.StartsWith(firstNamePrefix, ignoreCase))
.Where(p => p.LastName.StartsWith(lastNamePrefix, ignoreCase))
.Where(p => p.DOB.Equals(search.DOB ?? p.DOB))
.ToList();
}
P.S. I took the liberty to invert your first condition, that checked argument for null.
Upvotes: 0
Reputation: 34947
I suggest an approach with less return
s.
Here's my attempt:
/// <summary>
/// Returns a filtered list of persons
/// </summary>
/// <param name="search">Filters. Only filters that are set (not null or empty) are applied</param>
/// <param name="persons">List to filter</param>
/// <returns>Filtered list or a new list of all persons if no filters provided</returns>
/// <exception cref="ArgumentNullException"> Thrown if 'search' or 'persons' is null </exception>
static List<Person> Filter(SearchParam search, IEnumerable<Person> persons)
{
if( search == null ) throw new ArgumentNullException(nameof(search));
if (persons == null) throw new ArgumentNullException(nameof(persons));
IEnumerable<Person> filtered = persons;
if( !string.IsNullOrEmpty(search.FirstName))
{
filtered = filtered.Where( p => string.Compare( p.FirstName, search.FirstName, StringComparison.CurrentCultureIgnoreCase ) == 0);
}
if (!string.IsNullOrEmpty(search.LastName))
{
filtered = filtered.Where(p => string.Compare(p.LastName, search.LastName, StringComparison.CurrentCultureIgnoreCase) == 0);
}
if (search.DOB.HasValue)
{
//This filter should probably allow searching only by year, etc.
filtered = filtered.Where(p =>p.DOB == search.DOB);
}
return filtered.ToList();
}
And the example
List<Person> l = new List<Person>();
l.Add(new Person
{
FirstName = "Prashant",
DOB = new DateTime(1990, 01, 02)
});
l.Add(new Person
{
FirstName = "TymTam",
LastName = "No Choc",
DOB = new DateTime(1977, 01, 02)
});
l.Add(new Person
{
FirstName = "Melissa",
LastName = "No Choc",
DOB = new DateTime(1977, 01, 02)
});
var filter = new SearchParam()
{
LastName = "No CHOC",
DOB = new DateTime(1977, 01, 02)
};
var filtered = Filter(filter, l);
foreach( var f in filtered)
{
Console.WriteLine($"{f.FirstName} {f.LastName} ({f.DOB})");
}
Result:
TymTam No Choc (2/01/1977 00:00:00)
Melissa No Choc (2/01/1977 00:00:00)
Don't forget about Unit Tests!
Upvotes: 1
Reputation: 50110
Use Linqs pipelining
var workingList = persons;
if(searchParam.FirstName != null)
workingList = workingList.Where(p=>p.FirstName.Startswith(searchParam.FirstName));
if(searchParam.LastName != null)
workingList = workingList.Where(p=>p.LAstName.StartsWith(searchParam.LastName));
etc.
Finally
return workingList.ToList();
ie assemble the filters one at a time and then do the enumeration at the end
Upvotes: 2