Skip to content

A Swift package that provides a convenient way to sort sequences using multiple key paths and custom sort descriptors, including both returning a new sorted array and in-place sorting.

Notifications You must be signed in to change notification settings

imhanhan/MultiKeyPathSort

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MultiKeyPathSort

A Swift package that provides a convenient way to sort sequences using multiple key paths and custom sort descriptors, including both returning a new sorted array and in-place sorting.

Overview

MultiKeyPathSort simplifies sorting collections by allowing you to define multiple sorting criteria using key paths. It supports sorting by both optional and non-optional properties, allows you to specify the sorting order (ascending or descending), and control how nil values are handled. The package now also includes an in-place sort function for mutable collections.

Features

  • Sort by Multiple Key Paths: Define multiple levels of sorting using an array of sort descriptors.
  • Optional Property Sorting: Easily sort optional properties with control over nil value placement.
  • Custom Sorting Order: Specify ascending or descending order for each sort criterion.
  • In-Place Sorting: Sort mutable collections in place without creating a new array.
  • Type-Safe and Flexible: Leverages Swift's type system and key paths for safe and flexible sorting.

Installation

Swift Package Manager

Add MultiKeyPathSort to your project using Swift Package Manager:

  1. In Xcode, go to File > Add Packages.
  2. Enter the repository URL: https://github.com/yourusername/MultiKeyPathSort.git.
  3. Choose the package and add it to your project.

Usage

Import the Module

import MultiKeyPathSort

Define Your Model

Create a model that you want to sort. For example:

struct Person {
    let name: String
    let age: Int
    let height: Double?
}

Create Sort Descriptors

Define sorting criteria using SortDescriptor:

Sorting by a Non-Optional Property

let sortByAge = SortDescriptor(\Person.age, ascending: true)

Sorting by an Optional Property with nil Values First

let sortByHeight = SortDescriptor(\Person.height, ascending: true, nilFirst: true)

Sort Your Collection

Returning a New Sorted Array

Use the sorted(by:) method on your sequence:

let people = [
    Person(name: "Alice", age: 30, height: 5.5),
    Person(name: "Bob", age: 25, height: nil),
    Person(name: "Charlie", age: 35, height: 6.0)
]

let sortedPeople = people.sorted(by: [sortByAge, sortByHeight])

In-Place Sorting of Mutable Collections

If you have a mutable collection, you can sort it in place:

var people = [
    Person(name: "Alice", age: 30, height: 5.5),
    Person(name: "Bob", age: 25, height: nil),
    Person(name: "Charlie", age: 35, height: 6.0)
]

people.sort(by: [sortByAge, sortByHeight])

Handling nil Values

When sorting optional properties, you can specify where nil values should be placed:

  • nilFirst = true: nil values will appear before non-nil values.
  • nilFirst = false: nil values will appear after non-nil values.

Sorting in Descending Order

Set ascending to false to sort in descending order:

let sortByAgeDescending = SortDescriptor(\Person.age, ascending: false)

Full Example

import MultiKeyPathSort

struct Person {
    let name: String
    let age: Int
    let height: Double?
}

var people = [
    Person(name: "Alice", age: 30, height: 5.5),
    Person(name: "Bob", age: 30, height: nil),
    Person(name: "Charlie", age: 25, height: 6.0),
    Person(name: "Diana", age: 25, height: 5.8)
]

let sortByAge = SortDescriptor(\Person.age)
let sortByHeight = SortDescriptor(\Person.height, ascending: true, nilFirst: true)

// In-place sorting
people.sort(by: [sortByAge, sortByHeight])

for person in people {
    print("\(person.name): Age \(person.age), Height \(person.height ?? 0)")
}

Output:

Diana: Age 25, Height 5.8
Charlie: Age 25, Height 6.0
Bob: Age 30, Height 0.0
Alice: Age 30, Height 5.5

API Reference

SortDescriptor

A structure representing a sort descriptor that defines sorting criteria for elements of a sequence.

Initializers

  • Non-Optional Property

    init<T: Comparable>(_ keyPath: KeyPath<Element, T>, ascending: Bool = true)
    • keyPath: The key path to the property to sort by.
    • ascending: A Boolean value indicating whether the sort is ascending (true) or descending (false).
  • Optional Property

    init<T: Comparable>(_ keyPath: KeyPath<Element, T?>, ascending: Bool = true, nilFirst: Bool = true)
    • keyPath: The key path to the optional property to sort by.
    • ascending: A Boolean value indicating whether the sort is ascending (true) or descending (false).
    • nilFirst: A Boolean value indicating whether nil values should appear first (true) or last (false).

Sequence Extension

  • Sorted by Descriptors

    func sorted(by descriptors: [SortDescriptor<Element>]) -> [Element]

    Returns a new array containing the sequence's elements sorted according to the given sort descriptors.

MutableCollection Extension

  • In-Place Sort by Descriptors

    mutating func sort(by descriptors: [SortDescriptor<Element>])

    Sorts the collection in place according to the given sort descriptors.

Testing

You can write tests using your preferred testing framework to ensure the sorting behaves as expected. Here's an example using Swift's XCTest framework:

import XCTest
@testable import MultiKeyPathSort

final class MultiKeyPathSortTests: XCTestCase {
    struct Person {
        let name: String
        let age: Int
        let height: Double?
    }

    func testSortByMultipleKeyPaths() {
        var people = [
            Person(name: "Alice", age: 30, height: 5.5),
            Person(name: "Bob", age: 30, height: nil),
            Person(name: "Charlie", age: 25, height: 6.0),
            Person(name: "Diana", age: 25, height: 5.8)
        ]
        let sortByAge = SortDescriptor(\Person.age)
        let sortByHeight = SortDescriptor(\Person.height, ascending: true, nilFirst: true)
        people.sort(by: [sortByAge, sortByHeight])
        let expectedOrder = ["Diana", "Charlie", "Bob", "Alice"]
        XCTAssertEqual(people.map { $0.name }, expectedOrder)
    }
}

Contributing

Contributions are welcome! If you have ideas for improvements or have found a bug, please open an issue or submit a pull request.

Steps to Contribute

  1. Fork the repository on GitHub.

  2. Clone your fork:

    git clone https://github.com/yourusername/MultiKeyPathSort.git
  3. Create a new branch:

    git checkout -b feature/your-feature-name
  4. Make your changes and commit:

    git commit -am 'Add your message here'
  5. Push to the branch:

    git push origin feature/your-feature-name
  6. Open a pull request on GitHub.

License

MultiKeyPathSort is available under the MIT license. See the LICENSE file for more info.

Contact

For questions or suggestions, feel free to open an issue or contact me at [email protected].

About

A Swift package that provides a convenient way to sort sequences using multiple key paths and custom sort descriptors, including both returning a new sorted array and in-place sorting.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages