Reputation: 3182
I have a list of objects representing plants - each of which have member properties which represent a range of tolerable environmental conditions.
I want to re-order this list such that the plant objects are ranked in order of suitability.
I figure I want to give each item in the list a rank for temperature/pH suitability based on the proximity of the middle of their temperature/pH range to the environment data supplied.
I would then average the ranks and sort the list by this number.
However, I'm unsure what the best approach would be for tracking the ranks given to each item in the list. Does anybody have any recommendations on how best to approach this?
Upvotes: 2
Views: 3330
Reputation: 34418
Assuming you want to display the various suitability criteria rather than just an ordered plant list, I think you'll need to define a class with the extra data:
class PlantRankings
{
public Plant Plant { get; set; }
public double PhSuitabilityScore { get; set; }
public double SoilTypeScore { get; set; }
public double SmellsNiceScore { get; set; }
public double RankingScore { get; set; } // could compute on-the-fly here
}
and map your Plants into that class and then sort by the combined score there. I guess you'd write a method that accepted a Plant and your criteria then returned a ranking structure, e.g.
var rankedPlants = plants.Select(p => ScoreSuitability(p, criteria))
.OrderBy(pr => pr.RankingScore).ToList();
If by rank then you meant the 1-N ranking for each plant by each criteria then again I think you'll need to generate an extended structure but with
public int PhSuitabilityRank { get; set; }
alongside the scores; then once you've computed the score and built the list you can
int rank = 1;
for(var rankedPlant in
rankedPlants.OrderByDescending(pr => pr.PhSuitabilityScore))
{
rankedPlant.PhSuitabilityRank = rank;
++rank;
}
and so on. (There may be a way to do that in LINQ but without a .ForEach() on the Order results I think that's clearer and simpler.)
Upvotes: 0
Reputation: 1585
you can sort your planet list using linq or lembda expression with order by rank it will get you the sorted list.
Upvotes: 0
Reputation: 700680
You need a method to calculate the rank for an item, let's call it GetRank
, then you can use that in the Sort
method with a Comparison
:
plants.Sort((x,y) => GetRank(x).CompareTo(GetRank(y)));
You can also use the OrderBy
extension method which takes a delegate which returns the value for each item:
plants = plants.OrderBy(x => GetRank(x)).ToList();
The method for calculating the rank doesn't have to be a named method, you could put the code directly in the Comparison
or OrderBy
delegate by simply substituting GetRank(n)
with any expression you like.
Upvotes: 0
Reputation: 17166
You could do it like this:
var plants = new Plant[] { new Plant { T = 1, Ph = 2 }, new Plant { T = 2, Ph = 2 } };
var ps = from p in plants
let magicNumber = p.T/p.Ph // Or some other algorithm
orderby magicNumber
select p;
Then you can just create any number you like from the properties of a Plant
and you don't have to implement a Comparer.
Upvotes: 2
Reputation: 160982
In your case it sounds like you would be best off with a custom comparer that you can pass your environment settings:
class PlantComparer : IComparer<Plant>
{
public PlantComparer(PlantEnvironmentSettings settings)
{
}
public int Compare(Plant plant1, Plant plant2)
{
//compare two plants, return 0, 1 or -1
return 0;
}
}
Then you can use it in a sort:
List<Plant> plants = new List<Plant>();
..
PlantEnvironmentSettings settings = new PlantEnvironmentSettings();
plants.Sort(new PlantComparer(settings));
Upvotes: 0
Reputation: 16018
Expose the method for calculating suitability in your class, then use the LINQ OrderBy
extension
public int GetSuitabilityIndex()
{
//Calculate suitability..
}
var sorted = myList.OrderBy(item=>item.GetSuitabilityIndex());
Upvotes: 0
Reputation: 41256
You can use the LINQ OrderBy extension method. Now, typically you could write it like so:
mySet.OrderBy(x => x.SomeProperty)
However, if you want to order by multiple properties, you can simply create a method to define a value:
mySet.OrderBy(x => CreateValueFor(x))
And then CreateValueFor
returns back a specific value. For example, creating some integer that defines it's suitability, which is really a function of some properties on your object.
Upvotes: 0
Reputation: 14517
Can't you simply call the Sort method, passing in a Comparison method that evaluates in exactly the way you just described?
Upvotes: -1