Ранжирование объектов в списке по нескольким критериям

#c# #list #ranking

#c# #Список #Рейтинг

Вопрос:

У меня есть список объектов, представляющих растения, у каждого из которых есть свойства-члены, которые представляют диапазон допустимых условий окружающей среды.

Я хочу изменить порядок этого списка таким образом, чтобы объекты plant были ранжированы в порядке их пригодности.

Я полагаю, что хочу присвоить каждому элементу в списке ранг по пригодности для температуры / pH на основе близости середины их диапазона температуры / pH к предоставленным данным об окружающей среде.

Затем я бы усреднил ранги и отсортировал список по этому номеру.

Однако я не уверен, каким был бы наилучший подход для отслеживания рангов, присвоенных каждому элементу в списке. Есть ли у кого-нибудь какие-либо рекомендации о том, как лучше всего подойти к этому?

Ответ №1:

Вы могли бы сделать это следующим образом:

 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;
  

Тогда вы можете просто создать любое число, которое вам нравится, из свойств Plant и вам не нужно внедрять средство сравнения.

Ответ №2:

Вы можете использовать метод расширения LINQ OrderBy. Теперь, как правило, вы могли бы написать это следующим образом:

  mySet.OrderBy(x => x.SomeProperty)
  

Однако, если вы хотите упорядочить объекты по нескольким свойствам, вы можете просто создать метод для определения значения:

 mySet.OrderBy(x => CreateValueFor(x))
  

А затем CreateValueFor возвращает определенное значение. Например, создание некоторого целого числа, которое определяет его пригодность, что на самом деле является функцией некоторых свойств вашего объекта.

Ответ №3:

Предоставьте метод для вычисления пригодности в вашем классе, затем используйте расширение LINQ OrderBy

 public int GetSuitabilityIndex()
{
     //Calculate suitability..
}


var sorted = myList.OrderBy(item=>item.GetSuitabilityIndex());
  

Ответ №4:

В вашем случае, похоже, вам лучше всего использовать пользовательский компаратор, которому вы можете передавать настройки своей среды:

 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;
    }
}
  

Затем вы можете использовать это для сортировки:

 List<Plant> plants = new List<Plant>();
..
PlantEnvironmentSettings settings = new PlantEnvironmentSettings();
plants.Sort(new PlantComparer(settings));
  

Ответ №5:

Вам нужен метод для вычисления ранга элемента, давайте назовем его GetRank , затем вы можете использовать его в Sort методе с Comparison :

 plants.Sort((x,y) => GetRank(x).CompareTo(GetRank(y)));
  

Вы также можете использовать OrderBy метод расширения, который принимает делегат, возвращающий значение для каждого элемента:

 plants = plants.OrderBy(x => GetRank(x)).ToList();
  

Метод для вычисления ранга не обязательно должен быть именованным методом, вы можете поместить код непосредственно в делегат Comparison или OrderBy , просто заменив GetRank(n) любым выражением, которое вам нравится.

Ответ №6:

вы можете отсортировать свой список планет, используя выражение linq или lembda с порядком по рангу, это даст вам отсортированный список.

Ответ №7:

Предполагая, что вы хотите отобразить различные критерии пригодности, а не просто упорядоченный список растений, я думаю, вам нужно будет определить класс с дополнительными данными:

 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
}
  

и сопоставьте ваши растения с этим классом, а затем отсортируйте по их суммарному баллу. Я думаю, вы бы написали метод, который принимает завод, а ваши критерии затем возвращают структуру ранжирования, например

 var rankedPlants = plants.Select(p => ScoreSuitability(p, criteria))
                         .OrderBy(pr => pr.RankingScore).ToList();
  

Если под рангом вы имели в виду ранжирование 1-N для каждого объекта по каждому критерию, то опять же, я думаю, вам нужно будет сгенерировать расширенную структуру, но с

 public int PhSuitabilityRank { get; set; }
  

наряду с оценками; затем, как только вы вычислили оценку и построили список, вы можете

 int rank = 1;
for(var rankedPlant in
           rankedPlants.OrderByDescending(pr => pr.PhSuitabilityScore))
{
    rankedPlant.PhSuitabilityRank = rank;
      rank;
}
  

и так далее. (Возможно, есть способ сделать это в LINQ, но без .ForEach() по результатам упорядочивания я думаю, что это понятнее и проще.)

Ответ №8:

Разве вы не можете просто вызвать метод сортировки, передав метод сравнения, который вычисляет точно так, как вы только что описали?