#c# #sorting
#c# #сортировка
Вопрос:
Я играл с этим уже довольно давно, но не мог понять это или найти существующий вопрос об этом. Я пишу инструмент C # для подсчета очков в гонках, где мне нужно получить общий результат. Для этого результата применяются некоторые специальные правила, которые я не могу придумать, как это сделать наилучшим образом:
У меня есть список с результатами гонки (победитель получает 0 очков, 2-й получает 2, 3-й получает 3 и т. Д.). Чтобы результаты работали, мы сначала упорядочиваем по сумме всех точек. Когда это будет сделано, все еще существует вероятность того, что драйверы разделят одинаковое количество баллов. В этом случае мы должны посмотреть на их наилучшие результаты, например:
драйвер 1 набрал: 0 0 4 = 4 водитель 2 набрал очки: 2 2 0 = 4
В этом случае драйвер 1 будет первым, потому что у него больше всего выигрышей, драйвер 2 будет следовать, потому что у него только одна победа. Это должно применяться ко всем участникам.
Обновление: модель данных, которую я имею, выглядит следующим образом:
public class SerieResultForPilot {
public long Position { get; set; }
public Pilot Pilot { get; set; }
public List<SerieResultEntry> SerieResultEntries { get; set; }
public long Total { get; set; }
}
public class SerieResultEntry {
public long Points { get; set; }
public long Penalties { get; set; }
}
Порядок, который у меня есть в настоящее время, но работает неправильно:
var orderedList = serieResultList.OrderBy(rfp => rfp.Total);
for (int i = 0; i < pilots.Count; i ) {
orderedList = orderedList.ThenBy(c => c.SerieResultEntries.Count(sre => sre.Points == i));
}
Я надеюсь, что кто-нибудь может помочь мне с решением этой проблемы, поскольку я пока не смог найти здесь подобную проблему.
Заранее спасибо, отметьте
Решение Функция сравнения
public class SerieResultForPilot {
public long Position { get; set; }
public Pilot Pilot { get; set; }
public List<SerieResultEntry> SerieResultEntries { get; set; }
public long Total { get; set; }
public long CompareTo(SerieResultForPilot other) {
var result = this.Total - other.Total;
if (result != 0) {
return resu<
}
var thisResults = this.SerieResultEntries.OrderBy(x => x.Points).Select(x => x.Points).ToArray();
var otherResults = other.SerieResultEntries.OrderBy(x => x.Points).Select(x => x.Points).ToArray();
for (var i = 0; i < thisResults.Length; i ) {
if (thisResults[i] != otherResults[i]) {
return thisResults[i] - otherResults[i];
}
}
return 0;
}
}
public class SerieResultEntry {
public long Points { get; set; }
public long Penalties { get; set; }
}
Упорядочение
var orderedList = serieResultList.OrderBy(rfp => rfp.Total);
foreach (var result in serieResultList) {
orderedList = orderedList.ThenBy(c => c.CompareTo(result));
}
Комментарии:
1. Пожалуйста, не позволяйте нам предполагать и публиковать здесь некоторые из ваших кодов и примеров
2. Похоже, это похоже на решение проблемы программирования. Пожалуйста, опубликуйте свой код
3. Не могли бы вы также предоставить нам дополнительную информацию о вашей модели данных.
4. Как вы проводите различие между 5-кратным победителем и 5-кратным на 4-м месте?
5. Я обновил свой вопрос с использованием модели данных. @mybirthname В этом случае, я полагаю, у них не будет одинаковых очков для общего подсчета очков, поэтому 5-кратный победитель будет выше 5-кратного 4-го при первом заказе по общему количеству очков
Ответ №1:
вы можете реализовать IComparable
интерфейс в построении класса вокруг результата.
в соответствии с вашей моделью данных метод сравнения может выглядеть примерно так
public int CompareTo(SerieResultForPilot other){
var result this.Total - other.Total;
if (result != 0){
return resu<
}else{
var thisResults = this.SerieResultEntries.OrderBy(x => x.SerieResultEntries.Points).toArray();
var otherResults = his.SerieResultEntries.OrderBy(x => x.SerieResultEntries.Points).toArray();
for (var i=0; i< thisResults.Count; i ){
if (thisResults[i] != otherResults[i]){
return thisResults[i] - otherResults[i];
}
}
return 0;
}
}
документация по IComparable
интерфейсу доступна здесь https://msdn.microsoft.com/pl-pl/library/system.icomparable (v = против 110).aspx
Комментарии:
1. Спасибо, это было то, что мне было нужно! Как вы сказали в своем другом ответе, это действительно для landsailing, у нас отбрасывается каждые 4 гонки, но результаты уже помечены как отбрасываемые, поэтому реализовать это должно быть довольно легко. Я обновлю свой пост рабочей версией.
Ответ №2:
Возможно, не самый эффективный, но я думаю, что это сделает это:
drivers.OrderBy(x => new { x.Sum(y => y.Points),
x.Sum(y => y.Points.Where(t => t.Points = 4)), x.Sum(y => y.Points.Where(t => t.Points = 3)) });
Предполагая, что точки являются перечислимыми, сохраненными для каждого драйвера.
Ответ №3:
Глядя на ваш код, я думаю, все, что вам нужно сделать, это заменить ThenBy
на ThenByDescending
. (Вы хотите, чтобы драйверы с самыми низкими оценками находились в верхней части списка.) Это также зависит от того, что максимальный результат гонки меньше, чем количество водителей — может быть, вам нужно <=
, а не <
в вашем for
цикле?
Это не самый эффективный способ сделать это, но он довольно умный — я бы с трудом придумал что-то, что использовало бы меньше строк кода.
Комментарии:
1. Это то, с чем я играл, но не дает результата, который я ищу.
Ответ №4:
Сначала вам нужно найти no. выигрышей и суммы очков каждого водителя, а затем сортировка записей на основе их очков и выигрышей, как показано в примере ниже:
public class LinqUtil<T> where T : BaseClass
{
public static void MyScore()
{
List<DriverScore> scores = new List<DriverScore>
{
new DriverScore {driverId="driver2",score=2 },
new DriverScore {driverId="driver2",score=2 },
new DriverScore {driverId="driver2",score=0 },
new DriverScore {driverId="driver1",score=0 },
new DriverScore {driverId="driver1",score=0 },
new DriverScore {driverId="driver1",score=4 },
};
var _score = (from s in scores
group s by s.driverId into g
select new
{
driverId = g.Key,
Win = g.Count(x => x.score == 0),
Score = g.Sum(x => x.score)
}).OrderByDescending(x=>x.Score).ThenByDescending(x=>x.Win);
foreach(var _s in _score)
{
Console.WriteLine(_s.driverId " " _s.Win " " _s.Score);
}
}
}