问题描述
我有一组自定义对象.这些对象具有自定义的枚举var'type'.不同的类型如下:
I have an array of custom objects. The objects have a custom enum var 'type'. The different types are as follows:
- .movie
- .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 Kind
s.
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)
输出
基数排序-更快的排序
由于所有索引都是唯一的,因此我们可以使用基数排序创建 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 nil
s (empty slots) with compactMap()
. This sorting algorithm is O(n) instead of O(n log n) like the general sorting algorithm.
这篇关于iOS Swift-按枚举模式对数组进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!