iOS Swift-按枚举模式对数组进行排序 [英] iOS Swift - Sort array by enum pattern

查看:64
本文介绍了iOS Swift-按枚举模式对数组进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组自定义对象.这些对象具有自定义的枚举var'type'.不同的类型如下:

I have an array of custom objects. The objects have a custom enum var 'type'. The different types are as follows:

  • .movi​​e
  • .tv
  • .trailer
  • .genre
  • .article

我想按模式[电影,电视,预告片,流派,文章,电影,电视,预告片,流派,文章等...]对数组进行排序

I would like to sort the array by a pattern [movie, tv, trailer, genre, article, movie, tv, trailer, genre, article, ....etc]

我已经使枚举符合可比性,但是(也许我误会了),如果我按类型排序,则不会像这样对数组进行排序:

I have made the enum conform to comparable but (perhaps I am mistaken), if I sort by type won't it sort the array as such:

[movie, movie, movie, tv, tv, tv, trailer, trailer, trailer, etc...]

..实际上我希望它们一个接一个地以某种模式出现.

..when in fact I want them in a pattern one type after another.

[movie, tv, trailer, genre, article, movie, tv, trailer, genre, article, movie, tv, trailer, genre, article, and so on ...]

推荐答案

这里是一种解决方法.首先使用 map 将排序 Int index 与每个项目相关联.使用字典来跟踪与每个 Kind 相关的最后一个索引,并将其递增不同种类的数量.这将为数组中的每个项目提供唯一的排序索引,由于增加了重复的 Kind s

Here is one way to approach it. First use map to associate a sorting Int index with each item. Use a dictionary to keep track of the last index associated with each Kind and increment it by the number of different kinds. This will give a unique sorting index to every item in your array with items being sorted into the desired patten due to the increments added to repeated Kinds.

enum Kind: Int, CaseIterable {
    case movie, tv, trailer, genre, article
}

struct Item: CustomStringConvertible {
    var description: String { "\(name): \(kind)" }
    
    let id: Int
    let name: String
    let kind: Kind
}

let items: [Item] = [
    .init(id:  1, name: "D", kind: .tv),
    .init(id:  2, name: "B", kind: .movie),
    .init(id:  3, name: "F", kind: .trailer),
    .init(id:  4, name: "H", kind: .genre),
    .init(id:  5, name: "J", kind: .article),
    .init(id:  6, name: "C", kind: .tv),
    .init(id:  7, name: "A", kind: .movie),
    .init(id:  8, name: "E", kind: .trailer),
    .init(id:  9, name: "G", kind: .genre),
    .init(id: 10, name: "I", kind: .article)]

// Dictionary used to generate a unique sorting index for each kind
var dict: [Kind: Int] = [:]

typealias IndexedItem = (index: Int, element: Item)

// Assign a sorting index to each item.  Repeated Kinds will be incremented by
// allCases.count so that they sort into the next group
let items2: [IndexedItem] = items.map { item in
    dict[item.kind, default: item.kind.rawValue] += Kind.allCases.count
    return (dict[item.kind]!, item)
}

let result = items2.sorted { $0.index < $1.index }.map(\.element)
print(result)

输出

[B:电影,D:电视,F:预告片,H:类型,J:文章,A:电影,C:电视,E:预告片,G:类型,I:文章]

[B: movie, D: tv, F: trailer, H: genre, J: article, A: movie, C: tv, E: trailer, G: genre, I: article]


基数排序-更快的排序

由于所有索引都是唯一的,因此我们可以使用基数排序创建 result 数组:

Since all of the indices are unique, we can create the result array with a radix sort:

// Assign a sorting index to each item.  Repeated Kinds will be incremented by
// allCases.count so that they sort into the next group
let cases = Kind.allCases.count
let items2: [IndexedItem] = items.map { item in
    dict[item.kind, default: item.kind.rawValue - cases] += cases
    return (dict[item.kind]!, item)
}

// Use a radix sort to order the items
let maxIndex = dict.values.max() ?? -1
var slots = [Item?](repeating: nil, count: maxIndex + 1)
items2.forEach { slots[$0.index] = $0.element }
let result = slots.compactMap { $0 }

这相当于创建一个 nil 数组,该数组足够容纳最大的索引,使用它们的 index 将项目放入该数组,然后删除nil (空插槽)和 compactMap().这种排序算法是O(n),而不是常规排序算法那样的O(n log n).

This amounts to creating an array of nil large enough to hold the largest index, putting the items into the array using their index, and then removing the nils (empty slots) with compactMap(). This sorting algorithm is O(n) instead of O(n log n) like the general sorting algorithm.

这篇关于iOS Swift-按枚举模式对数组进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆