How can I get the object from a list of objects based on price?
With LINQ
we can use the .Where()
method to construct an IEnumerable
object that is filled by iterating every element of a collection and running some provided function on each element, if the function returns true
then the element is added to the result, if it's false
it's ignored.
With that we can 'search', if you will, a list.
Let's find all the pharmacies that contain the drug we're looking for
// define an easier to read function that will tell is if an inventory has a drug
bool ContainsDrug(string DrugName, IEnumerable<InventoryItem> Inventory)
{
foreach(var item in Inventory)
{
if(item.ToUpper().Equals(DrugName))
{
return true;
}
}
return false;
}
// get a enumerable that tells us which pharmacies have the drug
var pharmaciesContainingNyQuil = pharmacyList.Where(pharmacy => ContainsDrug("NyQuil", pharmacy.Inventory));
Now that we have all the pharmacies that contain the drug we should sort them by the price of that drug.
For that we will need to use 2 different LINQ
commands.
The .Select()
command iterates over the enumerable and creates a NEW enumerable with a NEW type based on whatever you return from the function you give the method.
For example to convert a int[]
to a string[]
we can use the select command.
It will iterate through the int[]
and run the function string UnamedLamda(int num) return num.ToString();
on each element and build 'a new enumerable' that only contains strings.
var strings = new int[]{1,2,3,4}.Select( num => num.ToString());
// outputs
strings = {"1","2","3","4"}
We can use that to convert all the pharmacies into an enumerable object that are a bit easier to sort.
To sort we can use the .Sort()
System.Collections.Generic
command. It's actually fairly simple. We provide .Sort()
with a lambda expression just like .Where()
and .Select()
but this time we give it two parameters left and right(they don't have to be named that way). System.Collections.Generic
then iterates through the enumerable and compares each left with each right and sorts them that way.
For example, if we wanted to sort a list of strings by the length of the strings we could use:
List<string> strs = {"1","two", "three", "four"};
// sort the list
strs.Sort((left,right) => left.Length.CompareTo(right.Length));
// this returns
{"1","two","four", "three"}
If we use these two commands we can make a new enumerable that is super easy to sort
decimal FindPrice(string Drug, IEnumerable<InventoryItem> Inventory)
{
foreach(var item in Inventory)
{
if(item.ToUpper().Equals(Drug))
{
return item.Cost;
}
}
}
var pharmaciesInEasyToSortTuples = pharmaciesContainingNyQuil.Select(pharmacy => (pharmacy, FindPrice("NyQuil",pharmacy.Inventory)));
// sort the pharmacies
var sortedPharmacies = pharmaciesInEasyToSortTuples.ToArray().Sort((left,right)=>left.item2.CompareTo(right.item2));
// return the lowest price
return sortedPharmacies?.FirstOrDefault().pharmacy ?? default;
Now if we put it all together we can get a final method that does what you want it to do, it could look something like this:
Pharmacy FindDrugAtPharmacyWithLowestPrice(string Drug, IEnumerable<Pharmacy> Pharmacies)
{
// we should check every pharmacy
// we should check if the pharmacy has the drug
// after we have all the pharmacies that contain the drug, sort them by price and grab the lowest one,
// get the pharmacies that have the drug
string name = Drug.ToUpper();
// Pharmacies.Where -> looks through the pharmacies
// pharmacy => pharmacy.Inventory.Select(x => x.Drug.ToUpper()) -> creates a List<string>(not really) that we can check to see if it contains the drug
var pharmaciesContainingTheDrug =
// search the pharmacies
Pharmacies.Where(
pharmacy =>
// convert the inventory to a list of strings
pharmacy.Inventory.Select(x => x.Drug.ToUpper())
// check the inventory for the drug
.Contains(name));
if (pharmaciesContainingTheDrug?.Count() is null or 0)
{
// no pharmacies containing drug
return default;
}
// now we have a enumerable that has all the pharmacies that contain the drug
// sort by the lowest price
// first convert to a more usable format so we can sort
decimal GetPriceInList(string Drug, IEnumerable<InventoryItem> Inventory)
{
return Inventory.Where(x => x.Drug.ToUpper() == Drug)?.FirstOrDefault()?.Cost ?? default;
}
var sortedPharmacies = pharmaciesContainingTheDrug.Select(pharmacy => (pharmacy, GetPriceInList(name, pharmacy.Inventory)));
// don't bother continuing if for some reason we couldn't construct the enumerable tuples
if (sortedPharmacies?.Count() is null or 0)
{
return default;
}
// actually sort the pharmacies
sortedPharmacies.ToList().Sort((left, right) => left.Item2.CompareTo(right.Item2));
return sortedPharmacies?.FirstOrDefault().pharmacy ?? default;
}