Перейти к содержимому

Как отсортировать структуру по одному из параметров

  • автор:

Как сортировать массив структур по одному из параметров структуры?

Подскажите как отсортировать данную структуру по переменой sum_ball , и если совпадает то по last_name Как ни пробовал, ничего не получается, просто выдает какую-то ахинею. Раньше с таким не приходилось работать.

Student temp; for (int i = 0; i < k; i++) < for (int j = i; j < k; j++) < if (student[j].sum_ball < student[i].sum_ball) < temp.last_name = student[i].last_name; student[i].last_name = student[j].last_name; student[j].last_name = temp; //и так дали с другими >> > 

Ну например вот так, с массивами так можно а с структурами как? Это ж не правильно я понимаю

Отслеживать

219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков

задан 23 ноя 2017 в 14:35

65 7 7 бронзовых знаков

Приведите код, а мы его подправим. Нужно просто правильно написать компаратор и правильно передать его алгоритму сортировки.

Сортировка структур. STL Часть 13

Показанные в предыдущей части разнообразные сортировки — гибкий и красивый механизм на все случаи жизни. Вот только на практике сортировать в чистом виде последовательности почти никогда не приходится. Это всё из области учебно-показательных задач.

На практике куда чаще стоит задача сортировать достаточно объёмные структуры данных (объёмные даже не по своему размеру, а по числу своих полей). И сортировать (или пересортировывать) их предстоит по значениям самых разных полей этих самых структур. Но и здесь на помощь приходят алгоритмы STL, особенно при использовании их совместно с функторами.

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

Как сортировать по нескольким свойствам в Swift

Сортировка проста, если вы делаете это по одному критерию или одному свойству. В Swift уже есть функция для этого.

Вот пример, где мы сортируем массив int.

let numbers = [3, 5, 6, 1, 8, 2] let sortedNumbers = numbers.sorted < (lhs, rhs) in return lhs < rhs >// [1, 2, 3, 5, 6, 8]

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

Здесь у нас есть простая структура BlogPost с title сообщения и два поля со статистическими данными, pageView и sessionDuration.

struct BlogPost

А вот пример данных.

extension BlogPost

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

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

Что такое сортировка по нескольким критериям и свойствам

Сортировка по нескольким критериям означает сортировку, при которой мы сравниваем первые критерии, и только если первый критерий равен, мы переходим к следующему. Мы делаем это до тех пор, пока не найдем неравный критерий.

Псевдокод будет выглядеть примерно так:

let sortedObjects = objects.sorted < (lhs, rhs) in for (lhsCriteria, rhsCriteria) in [(lhsCrtria1, rhsCriteria1), (lhsCrtria2, rhsCriteria2), (lhsCrtria3, rhsCriteria3), . , (lhsCrtriaN, rhsCriteriaN)] < // if lhsCriteria == rhsCriteria < // continue > return lhsCriteria < rhsCriteria // > >

Мы прокручиваем список критериев, начиная с самого важного (первого).

Если критерии порядка равны и мы не можем определить порядок, мы переходим к следующему критерию.

Если мы можем определить порядок между двумя объектами по критериям, мы останавливаемся и возвращаем результат.

Если вам трудно понять псевдокод, не волнуйтесь. Я не профессиональный писатель псевдокода. Следующий пример должен прояснить ситуацию.

Сортировка массива объектов по двум полям

Мы будем использовать тот же сценарий, упомянутый выше. Мы хотим отсортировать BlogPost по производительности. Наша производительность определяется количеством просмотров страниц (pageView), и если посты в блоге имеют одинаковое количество просмотров страниц, мы используем продолжительность сеанса (sessionDuration).

Вот структура BlogPost и пример данных, которые мы использовали в предыдущем примере.

struct BlogPost < let title: String let pageView: Int let sessionDuration: Double >extension BlogPost

То, как мы измеряем производительность, можно перевести в этот код.

let popularPosts = BlogPost.examples.sorted < (lhs, rhs) in if lhs.pageView == rhs.pageView < // return lhs.sessionDuration > rhs.sessionDuration > return lhs.pageView > rhs.pageView // >

Если сообщения в блоге имеют один и тот же просмотр страницы, мы используем продолжительность сеанса.

Если количество просмотров страниц не равно, мы можем определить порядок просмотров страниц. (сортируем по убыванию)

Вот наш результат.

[BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0), BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0), BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0), BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0), BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)]

Сортировка массива объектов по трем полям

Как видите, выполнить сортировку по двум критериям очень просто. Давайте увеличим количество критериев в уравнении. Если посты в блоге имеют одинаковую эффективность, мы отсортируем их по имени.

Давайте добавим больше сообщений в блоге к нашим примерам.

extension BlogPost

Нет никакой разницы между двумя и тремя критериями. Мы можем использовать ту же логику, что и раньше.

let popularPosts = BlogPost.examples2.sorted < (lhs, rhs) in if lhs.pageView == rhs.pageView < if lhs.sessionDuration == rhs.sessionDuration < // return lhs.title < rhs.title >return lhs.sessionDuration > rhs.sessionDuration > return lhs.pageView > rhs.pageView >

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

[BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0), BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2.0), BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0), BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0), BlogPost(title: "Angero", pageView: 1, sessionDuration: 2.0), BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0), BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)]

Проблема

Мы можем использовать ту же логику для двух и трех критериев. Единственная проблема заключается в том, что чем больше критериев, тем больше вложенных if-else вам понадобится.

Вот пример нескольких критериев, которые могут привести к пирамиде гибели.

let popularPosts = BlogPost.examples2.sorted < (lhs, rhs) in if lhs.pageView == rhs.pageView < if lhs.sessionDuration == rhs.sessionDuration < if lhs.nextCriteria == rhs.nextCriteria < if lhs.nextCriteria == rhs.nextCriteria < . >. > . > return lhs.sessionDuration > rhs.sessionDuration > return lhs.pageView > rhs.pageView >

Сортировать массив объектов по N полям

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

let sortedObjects = objects.sorted < (lhs, rhs) in for (lhsCriteria, rhsCriteria) in [(lhsCrtria1, rhsCriteria1), (lhsCrtria2, rhsCriteria2), (lhsCrtria3, rhsCriteria3), . , (lhsCrtriaN, rhsCriteriaN)] < if lhsCriteria == rhsCriteria < continue >return lhsCriteria < rhsCriteria >>

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

extension BlogPost < static var examples2: [BlogPost] = [ BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2), BlogPost(title: "Alice", pageView: 1, sessionDuration: 3), BlogPost(title: "Peter", pageView: 1, sessionDuration: 2), BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1), BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2), BlogPost(title: "Abena", pageView: 4, sessionDuration: 10), BlogPost(title: "Angero", pageView: 1, sessionDuration: 2) ] >typealias AreInIncreasingOrder = (BlogPost, BlogPost) -> Bool // let popularPosts = BlogPost.examples2.sorted < (lhs, rhs) in let predicates: [AreInIncreasingOrder] = [ //  < $0.pageView >$1.pageView >, < $0.sessionDuration >$1.sessionDuration>, < $0.title < $1.title >] for predicate in predicates < // if !predicate(lhs, rhs) && !predicate(rhs, lhs) < // continue // > return predicate(lhs, rhs) // > return false >

Я объявляю псевдоним AreInIncreasingOrder, который соответствует закрытию сортировки. Это улучшает читаемость, когда мы объявляем нашу коллекцию предикатов.

Мы объявляем набор предикатов.

Мы перебираем предикаты.

Вот сложная часть, мы хотим проверить, могут ли критерии определять порядок сообщений в блоге или нет. Но AreInIncreasingOrder возвращает логическое значение. Как проверить, совпадает ли порядок? Прежде чем ответить на этот вопрос, рассмотрим определение AreInIncreasingOrder.

AreInIncreasingOrder — это предикат, который возвращает значение true, если его первый аргумент должен располагаться перед вторым аргументом; в противном случае ложно. Таким образом, два аргумента находятся в порядке равенства, только если оба аргумента не в порядке возрастания.

Если порядок равен, мы переходим к следующему предикату.

Если порядок не равен, мы можем использовать этот предикат для определения порядка.

[BlogPost(title: "Akosua", pageView: 5, sessionDuration: 2.0), BlogPost(title: "Zoo", pageView: 5, sessionDuration: 2.0), BlogPost(title: "Abena", pageView: 4, sessionDuration: 10.0), BlogPost(title: "Alice", pageView: 1, sessionDuration: 3.0), BlogPost(title: "Angero", pageView: 1, sessionDuration: 2.0), BlogPost(title: "Peter", pageView: 1, sessionDuration: 2.0), BlogPost(title: "Kofi", pageView: 1, sessionDuration: 1.0)]

Вывод

Недавно я просто наткнулся на этот вопрос и нашел его интересным. Это простая задача, которая занимает у меня некоторое время, чтобы понять.

Методы в этой статье не привязаны к Swift. Вы можете применить это к любому языку по вашему выбору. Вы можете улучшить код, чтобы сделать его более универсальным, поддерживающим любые объекты или свойства, которые вы хотите, и я оставляю это вашим упражнением. Если вы придумаете что-нибудь интересное, вы можете поделиться своим результатом со мной в Twitter. Хотелось бы увидеть вашу реализацию.

  • Next 14 полезных операторов массивов в Swift
  • Previous Декодировать массив с поврежденным элементом

Как отсортировать структуру по одному из параметров

Большинство встроенных в .NET классов коллекций и массивы поддерживают сортировку. С помощью одного метода, который, как правило, называется Sort() можно сразу отсортировать по возрастанию весь набор данных. Например:

int[] numbers = new int[] < 97, 45, 32, 65, 83, 23, 15 >; Array.Sort(numbers); foreach (int n in numbers) Console.WriteLine(n); // 15 23 32 45 65 83 97

Однако метод Sort по умолчанию работает только для наборов примитивных типов, как int или string. Для сортировки наборов сложных объектов применяется интерфейс IComparable . Он имеет всего один метод:

public interface IComparable

Метод CompareTo предназначен для сравнения текущего объекта с объектом, который передается в качестве параметра object? o . На выходе он возвращает целое число, которое может иметь одно из трех значений:

  • Меньше нуля. Значит, текущий объект должен находиться перед объектом, который передается в качестве параметра
  • Равен нулю. Значит, оба объекта равны
  • Больше нуля. Значит, текущий объект должен находиться после объекта, передаваемого в качестве параметра

Например, имеется класс Person:

class Person : IComparable < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(object? o) < if(o is Person person) return Name.CompareTo(person.Name); else throw new ArgumentException("Некорректное значение параметра"); >>

Здесь в качестве критерия сравнения выбрано свойство Name объекта Person. Поэтому при сравнении здесь фактически идет сравнение значения свойства Name текущего объекта и свойства Name объекта, переданного через параметр. Если вдруг объект не удастся привести к типу Person, то выбрасывается исключение.

var tom = new Person("Tom", 37); var bob = new Person("Bob", 41); var sam = new Person("Sam", 25); Person[] people = < tom, bob, sam>; Array.Sort(people); foreach (Person person in people) < Console.WriteLine($"- "); >

И в данном случае мы получим следующий консольный вывод:

Bob - 41 Sam - 25 Tom - 37

Интерфейс IComparable имеет обобщенную версию, поэтому мы могли бы сократить и упростить его применение в классе Person:

class Person : IComparable  < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(Person? person) < if(person is null) throw new ArgumentException("Некорректное значение параметра"); return Name.CompareTo(person.Name); >>

Аналогичным образом мы можем сравнивать по возрасту:

class Person : IComparable  < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >public int CompareTo(Person? person) < if(person is null) throw new ArgumentException("Некорректное значение параметра"); return Age - person.Age; >>

Применение компаратора

Кроме интерфейса IComparable платформа .NET также предоставляет интерфейс IComparer:

public interface IComparer

Метод Compare предназначен для сравнения двух объектов o1 и o2. Он также возвращает три значения, в зависимости от результата сравнения: если первый объект больше второго, то возвращается число больше 0, если меньше — то число меньше нуля; если оба объекта равны, возвращается ноль.

Создадим компаратор объектов Person. Пусть он сравнивает объекты в зависимости от длины строки — значения свойства Name:

class PeopleComparer : IComparer  < public int Compare(Person? p1, Person? p2) < if(p1 is null || p2 is null) throw new ArgumentException("Некорректное значение параметра"); return p1.Name.Length - p2.Name.Length; >> class Person < public string Name < get;>public int Age < get; set; >public Person(string name, int age) < Name = name; Age = age; >>

В данном случае используется обобщенная версия интерфейса IComparer, чтобы не делать излишних преобразований типов. Применение компаратора:

var alice = new Person("Alice", 41); var tom = new Person("Tom", 37); var kate = new Person("Kate", 25); Person[] people = < alice, tom, kate>; Array.Sort(people, new PeopleComparer()); foreach (Person person in people) < Console.WriteLine($"- "); >

Объект компаратора указывается в качестве второго параметра метода Array.Sort() . При этом не важно, реализует ли класс Person интерфейс IComparable или нет. Правила сортировки, установленные компаратором, будут иметь больший приоритет. В начале будут идти объекты Person, у которых имена меньше, а в конце — у которых имена длиннее:

Tom - 37 Kate - 25 Alice - 41

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *