Câu trả lời này chi tiết cách xáo trộn với thuật toán nhanh và đồng nhất (Fisher-Yates) trong Swift 4.2+ và cách thêm tính năng tương tự trong các phiên bản trước của Swift. Việc đặt tên và hành vi cho mỗi phiên bản Swift phù hợp với các phương pháp sắp xếp đột biến và không biến đổi cho phiên bản đó.
Swift 4.2+
shuffle
và shuffled
là bản gốc bắt đầu Swift 4.2. Ví dụ sử dụng:
let x = [1, 2, 3].shuffled()
// x == [2, 3, 1]
let fiveStrings = stride(from: 0, through: 100, by: 5).map(String.init).shuffled()
// fiveStrings == ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffle()
// numbers == [3, 2, 1, 4]
Swift 4.0 và 4.1
Các tiện ích mở rộng này thêm một shuffle()
phương thức vào bất kỳ bộ sưu tập có thể thay đổi nào (mảng và bộ đệm có thể thay đổi không an toàn) và một shuffled()
phương thức cho bất kỳ chuỗi nào:
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Cách sử dụng tương tự như trong ví dụ Swift 4.2 ở trên.
Swift 3
Các tiện ích mở rộng này thêm một shuffle()
phương thức vào bất kỳ bộ sưu tập có thể thay đổi nào và một shuffled()
phương thức cho bất kỳ chuỗi nào:
extension MutableCollection where Indices.Iterator.Element == Index {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 3.2
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
self.swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Iterator.Element] {
var result = Array(self)
result.shuffle()
return result
}
}
Cách sử dụng tương tự như trong ví dụ Swift 4.2 ở trên.
Swift 2
(ngôn ngữ lỗi thời: bạn không thể sử dụng Swift 2.x để xuất bản trên iTunes Connect bắt đầu từ tháng 7 năm 2018)
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled.
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
Sử dụng:
[1, 2, 3].shuffle()
// [2, 3, 1]
let fiveStrings = 0.stride(through: 100, by: 5).map(String.init).shuffle()
// ["20", "45", "70", "30", ...]
var numbers = [1, 2, 3, 4]
numbers.shuffleInPlace()
// [3, 2, 1, 4]
Swift 1.2
(ngôn ngữ lỗi thời: bạn không thể sử dụng Swift 1.x để xuất bản trên iTunes Connect bắt đầu từ tháng 7 năm 2018)
shuffle
như một phương pháp mảng đột biến
Tiện ích mở rộng này sẽ cho phép bạn xáo trộn một thể hiện có thể thay đổi Array
tại chỗ:
extension Array {
mutating func shuffle() {
if count < 2 { return }
for i in 0..<(count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
swap(&self[i], &self[j])
}
}
}
var numbers = [1, 2, 3, 4, 5, 6, 7, 8]
numbers.shuffle() // e.g., numbers == [6, 1, 8, 3, 2, 4, 7, 5]
shuffled
như một phương pháp mảng không biến đổi
Tiện ích mở rộng này sẽ cho phép bạn truy xuất một bản sao được xáo trộn Array
:
extension Array {
func shuffled() -> [T] {
if count < 2 { return self }
var list = self
for i in 0..<(list.count - 1) {
let j = Int(arc4random_uniform(UInt32(list.count - i))) + i
swap(&list[i], &list[j])
}
return list
}
}
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let mixedup = numbers.shuffled() // e.g., mixedup == [6, 1, 8, 3, 2, 4, 7, 5]