ฉันจะสุ่มหรือสุ่มองค์ประกอบภายในอาร์เรย์ใน Swift ได้อย่างไร ตัวอย่างเช่นหากอาร์เรย์ของฉันประกอบด้วยไพ่ 52 ใบฉันต้องการสลับแถวเพื่อสับไพ่
array.shuffle
ในทับทิมหนึ่งจะไปสำหรับ ไม่จำเป็นต้องใช้เวอร์ชันของคุณเอง ฉันเดาว่า OP กำลังมองหาสิ่งที่คล้ายกัน
ฉันจะสุ่มหรือสุ่มองค์ประกอบภายในอาร์เรย์ใน Swift ได้อย่างไร ตัวอย่างเช่นหากอาร์เรย์ของฉันประกอบด้วยไพ่ 52 ใบฉันต้องการสลับแถวเพื่อสับไพ่
array.shuffle
ในทับทิมหนึ่งจะไปสำหรับ ไม่จำเป็นต้องใช้เวอร์ชันของคุณเอง ฉันเดาว่า OP กำลังมองหาสิ่งที่คล้ายกัน
คำตอบ:
คำตอบนี้ให้รายละเอียดวิธีการสลับด้วยอัลกอริธึมที่รวดเร็วและสม่ำเสมอ (Fisher-Yates) ใน Swift 4.2+ และวิธีการเพิ่มฟีเจอร์เดียวกันใน Swift เวอร์ชันก่อนหน้าต่างๆ การตั้งชื่อและลักษณะการทำงานสำหรับ Swift แต่ละเวอร์ชันตรงกับวิธีการเรียงลำดับ mutating และ nonmutating
shuffle
และshuffled
เป็นภาษาเริ่มต้นของ Swift 4.2 ตัวอย่างการใช้งาน:
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]
ส่วนขยายเหล่านี้เพิ่มshuffle()
วิธีในการรวบรวมที่ไม่แน่นอน (อาร์เรย์และบัฟเฟอร์ที่ไม่แน่นอนที่ไม่ปลอดภัย) และshuffled()
วิธีการเรียงลำดับใด ๆ :
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
}
}
การใช้งานเช่นเดียวกับในตัวอย่าง Swift 4.2 ด้านบน
ส่วนขยายเหล่านี้เพิ่มshuffle()
วิธีในการรวบรวมที่ไม่แน่นอนและshuffled()
วิธีการในลำดับใด ๆ :
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
}
}
การใช้งานเช่นเดียวกับในตัวอย่าง Swift 4.2 ด้านบน
(ภาษาที่ล้าสมัย: คุณไม่สามารถใช้ Swift 2.x เพื่อเผยแพร่บน iTunes Connect ได้ตั้งแต่เดือนกรกฎาคม 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
}
}
การใช้งาน:
[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.x เพื่อเผยแพร่บน iTunes Connect ได้ตั้งแต่เดือนกรกฎาคม 2018)
shuffle
เป็นวิธีการกลายพันธุ์อาเรย์ส่วนขยายนี้จะช่วยให้คุณสามารถสลับArray
อินสแตนซ์ที่ไม่แน่นอนได้:
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
เป็นวิธีการอาเรย์ที่ไม่กลายพันธุ์ส่วนขยายนี้จะช่วยให้คุณดึงสำเนาที่สับได้ของ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]
countElements
จะหายไปและมันเปลี่ยนcount
ตอนนี้ส่งกลับT.Index.Distance
เพื่อให้ตอบสนองความต้องการข้อ จำกัด C.Index.Distance == Int
ที่จะอยู่ใน รุ่นนี้ควรใช้งานได้: gist.github.com/airspeedswift/03d07a9dc86fabdc370f
[1, 2].shuffled()
ควรจะกลับมา[2, 1]
ทุกครั้งหรือไม่
if count > 0
ที่ด้านบนของฟังก์ชั่นอาเรย์กลายพันธุ์เพื่อป้องกันการรับ "ข้อผิดพลาดร้ายแรง: ไม่สามารถสร้างช่วงที่มีปลาย <เริ่มต้น" เมื่อมันผ่านอาร์เรย์ที่ว่างเปล่า
guard i != j else { continue }
ก่อนการแลกเปลี่ยน ฉันยื่นเรดาร์ แต่พฤติกรรมใหม่นั้นมีเจตนา
shuffleInPlace
อาจมีปัญหาหากดัชนีการรวบรวมไม่เริ่มที่ศูนย์เช่นสำหรับการแบ่งส่วนอาร์เรย์ for i in 0..<count - 1
ควรเป็นfor i in startIndex ..< endIndex - 1
(และจากนั้นการแปลงเป็น Swift 3 แทบจะไม่สำคัญ)
แก้ไข: ดังที่ระบุไว้ในคำตอบอื่น ๆ Swift 4.2 ในที่สุดก็เพิ่มการสร้างตัวเลขสุ่มในไลบรารีมาตรฐานพร้อมด้วยการสับอาร์เรย์
อย่างไรก็ตามชุดGKRandom
/ GKRandomDistribution
ใน GameplayKit ยังคงมีประโยชน์กับRandomNumberGenerator
โปรโตคอลใหม่- หากคุณเพิ่มส่วนขยายใน GameplayKit RNGs เพื่อให้สอดคล้องกับโปรโตคอลไลบรารีมาตรฐานใหม่คุณสามารถรับ:
... และยังคงใช้ประโยชน์จาก API แบบสุ่ม "ดั้งเดิม" ใหม่ที่ดีใน Swift
ส่วนที่เหลือของคำตอบนี้เกี่ยวข้องกับ RNGs และ / หรือการใช้ในคอมไพเลอร์ Swift รุ่นเก่า
มีคำตอบที่ดีอยู่แล้วที่นี่และภาพประกอบที่ดีว่าทำไมการเขียนเพลงของคุณเองอาจทำให้เกิดข้อผิดพลาดได้ถ้าคุณไม่ระวัง
ใน iOS 9, macOS 10.11 และ tvOS 9 (หรือใหม่กว่า) คุณไม่จำเป็นต้องเขียนเอง มีการใช้งานที่มีประสิทธิภาพและถูกต้องของ Fisher-Yatesใน GameplayKit (ซึ่งแม้ว่าชื่อจะไม่ได้มีไว้สำหรับเกมเท่านั้น)
หากคุณต้องการสลับแบบที่ไม่ซ้ำใคร:
let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
หากคุณต้องการจำลองแบบสุ่มหรือชุดของสับให้เลือกและคัดสรรแหล่งสุ่มเฉพาะ เช่น
let lcg = GKLinearCongruentialRandomSource(seed: mySeedValue)
let shuffled = lcg.arrayByShufflingObjects(in: array)
ใน iOS 10 / MacOS 10.12 / tvOS 10 NSArray
นอกจากนี้ยังมีความสะดวกสบายสำหรับไวยากรณ์สับผ่านทางส่วนขยายบน แน่นอนว่าเป็นเรื่องยุ่งยากเล็กน้อยเมื่อคุณใช้ Swift Array
(และสูญเสียประเภทองค์ประกอบเมื่อกลับมาที่ Swift):
let shuffled1 = (array as NSArray).shuffled(using: random) // -> [Any]
let shuffled2 = (array as NSArray).shuffled() // use default random source
แต่มันเป็นเรื่องง่ายที่จะทำเสื้อคลุม Swift ที่รักษาประเภทไว้สำหรับมัน:
extension Array {
func shuffled(using source: GKRandomSource) -> [Element] {
return (self as NSArray).shuffled(using: source) as! [Element]
}
func shuffled() -> [Element] {
return (self as NSArray).shuffled() as! [Element]
}
}
let shuffled3 = array.shuffled(using: random)
let shuffled4 = array.shuffled()
let shuffled = lcg.arrayByShufflingObjects(in: array)
ในSwift 2.0 GameplayKit อาจมาช่วยชีวิต! (รองรับโดยiOS9หรือใหม่กว่า)
import GameplayKit
func shuffle() {
array = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(array)
}
import GameplayKit.GKRandomSource
นี่คือบางสิ่งที่สั้นกว่าเล็กน้อย:
sorted(a) {_, _ in arc4random() % 2 == 0}
sort
ฟังก์ชั่นต้องปิดเพื่อสั่งซื้อองค์ประกอบ การปิดนี้ใช้สองพารามิเตอร์ (elem1, elem2) และต้องส่งคืนจริงถ้าค่าแรกควรปรากฏขึ้นก่อนค่าที่สองและเท็จมิฉะนั้น ถ้าเรากลับบูลีนแบบสุ่มแทน ... จากนั้นเราก็รวมสิ่งทั้งหมด :)
arc4random_uniform()
เพราะในขณะนี้อยู่ภายใต้อคติโมดูโล ประการที่สองผลลัพธ์ขึ้นอยู่กับอัลกอริทึมการเรียงลำดับอย่างมาก (ซึ่งเราไม่รู้จักโดยไม่ได้ดูที่แหล่งที่มา)
collection.sorted { _,_ in arc4random_uniform(1) == 0 }
ใช้อัลกอริทึมของ Nateฉันต้องการดูว่าจะเป็นอย่างไรกับ Swift 2 และส่วนขยายโปรโตคอล
นี่คือสิ่งที่ฉันมาด้วย
extension MutableCollectionType where Self.Index == Int {
mutating func shuffleInPlace() {
let c = self.count
for i in 0..<(c - 1) {
let j = Int(arc4random_uniform(UInt32(c - i))) + i
swap(&self[i], &self[j])
}
}
}
extension MutableCollectionType where Self.Index == Int {
func shuffle() -> Self {
var r = self
let c = self.count
for i in 0..<(c - 1) {
let j = Int(arc4random_uniform(UInt32(c - i))) + i
swap(&r[i], &r[j])
}
return r
}
}
ทีนี้ใคร ๆMutableCollectionType
ก็สามารถใช้วิธีการเหล่านี้ได้เพราะมันใช้Int
เป็นIndex
ในกรณีของฉันฉันมีปัญหาบางอย่างในการสลับออบเจ็กต์ใน Array จากนั้นฉันก็เกาหัวของฉันและเดินไปเพื่อสร้างล้อใหม่
// swift 3.0 ready
extension Array {
func shuffled() -> [Element] {
var results = [Element]()
var indexes = (0 ..< count).map { $0 }
while indexes.count > 0 {
let indexOfIndexes = Int(arc4random_uniform(UInt32(indexes.count)))
let index = indexes[indexOfIndexes]
results.append(self[index])
indexes.remove(at: indexOfIndexes)
}
return results
}
}
นี่เป็นเวอร์ชั่นของการดำเนินการสับเปลี่ยน Fisher-YatesของNateสำหรับSwift 4 (Xcode 9)
extension MutableCollection {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
for i in indices.dropLast() {
let diff = distance(from: i, to: endIndex)
let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff))))
swapAt(i, j)
}
}
}
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Element] {
var list = Array(self)
list.shuffle()
return list
}
}
การเปลี่ยนแปลงคือ:
Indices.Iterator.Element == Index
นี้เป็นส่วนหนึ่งของCollection
โปรโตคอลและไม่จำเป็นต้องกำหนดไว้ในส่วนขยายอีกต่อไปswapAt()
ในการเก็บรวบรวมการเปรียบเทียบSE-0173 MutableCollection.swapAt(_:_:)
เพิ่มElement
Iterator.Element
เป็นนามแฝงสำหรับนี่คือสิ่งที่ฉันใช้:
func newShuffledArray(array:NSArray) -> NSArray {
var mutableArray = array.mutableCopy() as! NSMutableArray
var count = mutableArray.count
if count>1 {
for var i=count-1;i>0;--i{
mutableArray.exchangeObjectAtIndex(i, withObjectAtIndex: Int(arc4random_uniform(UInt32(i+1))))
}
}
return mutableArray as NSArray
}
Swift 4 สลับองค์ประกอบของอาร์เรย์ในการวนรอบที่ i คืออัตราส่วนการผสม
var cards = [Int]() //Some Array
let i = 4 // is the mixing ratio
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: Int(arc4random_uniform(UInt32(cards.count))))
cards.insert(card, at: Int(arc4random_uniform(UInt32(cards.count))))
}
}
หรือด้วยส่วนขยาย Int
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: cards.count.arc4random)
cards.insert(card, at: cards.count.arc4random)
}
}
extension Int {
var arc4random: Int {
if self > 0 {
print("Arc for random positiv self \(Int(arc4random_uniform(UInt32(self))))")
return Int(arc4random_uniform(UInt32(self)))
} else if self < 0 {
print("Arc for random negotiv self \(-Int(arc4random_uniform(UInt32(abs(self)))))")
return -Int(arc4random_uniform(UInt32(abs(self))))
} else {
print("Arc for random equal 0")
return 0
}
}
}
โซลูชัน Swift 3 ตามคำตอบ @Nate Cook: (ทำงานถ้าดัชนีเริ่มต้นด้วย 0 ดูความคิดเห็นด้านล่าง)
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
} }
extension MutableCollection 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 }
let countInt = count as! Int
for i in 0..<countInt - 1 {
let j = Int(arc4random_uniform(UInt32(countInt - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()
หลายครั้ง - ดูstackoverflow.com/a/37843901/1187415สำหรับวิธีแก้ไขที่ถูกต้อง
นี่คือวิธีที่ทำได้ในวิธีที่ง่ายที่สุด import Gamplaykit
สู่ VC ของคุณและใช้รหัสด้านล่าง ทดสอบใน Xcode 8
import GameplayKit
let array: NSArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
override func viewDidLoad() {
super.viewDidLoad()
print(array.shuffled())
}
หากคุณต้องการได้รับสตริงสับจากอาเรย์คุณสามารถใช้รหัสด้านล่าง ..
func suffleString() {
let ShuffleArray = array.shuffled()
suffleString.text = ShuffleArray.first as? String
print(suffleString.text!)
}
ด้วย Swift 3 หากคุณต้องการสลับอาเรย์เข้ากับตำแหน่งหรือรับอาเรย์แบบสับใหม่จากอาเรย์AnyIterator
สามารถช่วยคุณได้ แนวคิดคือการสร้างอาร์เรย์ของดัชนีจากอาเรย์ของคุณเพื่อสลับดัชนีเหล่านั้นด้วยAnyIterator
อินสแตนซ์และswap(_:_:)
ฟังก์ชันและเพื่อแมปองค์ประกอบขององค์ประกอบนี้AnyIterator
อินสแตนซ์กับองค์ประกอบที่เกี่ยวข้องของอาร์เรย์
รหัสสนามเด็กเล่นต่อไปนี้แสดงวิธีการทำงาน:
import Darwin // required for arc4random_uniform
let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
var indexArray = Array(array.indices)
var index = indexArray.endIndex
let indexIterator: AnyIterator<Int> = AnyIterator {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
let newArray = indexIterator.map { array[$0] }
print(newArray) // may print: ["Jock", "Ellie", "Sue Ellen", "JR", "Pamela", "Bobby"]
คุณสามารถ refactor รหัสก่อนหน้าและสร้างshuffled()
ฟังก์ชั่นภายในArray
ส่วนขยายเพื่อรับอาร์เรย์แบบสับใหม่จากอาร์เรย์:
import Darwin // required for arc4random_uniform
extension Array {
func shuffled() -> Array<Element> {
var indexArray = Array<Int>(indices)
var index = indexArray.endIndex
let indexIterator = AnyIterator<Int> {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
return indexIterator.map { self[$0] }
}
}
การใช้งาน:
let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
let newArray = array.shuffled()
print(newArray) // may print: ["Bobby", "Pamela", "Jock", "Ellie", "JR", "Sue Ellen"]
let emptyArray = [String]()
let newEmptyArray = emptyArray.shuffled()
print(newEmptyArray) // prints: []
เป็นทางเลือกแทนรหัสก่อนหน้าคุณสามารถสร้างshuffle()
ฟังก์ชั่นภายในArray
ส่วนขยายเพื่อสับเปลี่ยนอาร์เรย์ในสถานที่:
import Darwin // required for arc4random_uniform
extension Array {
mutating func shuffle() {
var indexArray = Array<Int>(indices)
var index = indexArray.endIndex
let indexIterator = AnyIterator<Int> {
guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
else { return nil }
index = nextIndex
let randomIndex = Int(arc4random_uniform(UInt32(index)))
if randomIndex != index {
swap(&indexArray[randomIndex], &indexArray[index])
}
return indexArray[index]
}
self = indexIterator.map { self[$0] }
}
}
การใช้งาน:
var mutatingArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
mutatingArray.shuffle()
print(mutatingArray) // may print ["Sue Ellen", "Pamela", "Jock", "Ellie", "Bobby", "JR"]
คุณสามารถใช้swap
ฟังก์ชั่นทั่วไปได้เช่นกันและใช้ Fisher-Yates ที่กล่าวถึง:
for idx in 0..<arr.count {
let rnd = Int(arc4random_uniform(UInt32(idx)))
if rnd != idx {
swap(&arr[idx], &arr[rnd])
}
}
หรือ verbose น้อยกว่า:
for idx in 0..<steps.count {
swap(&steps[idx], &steps[Int(arc4random_uniform(UInt32(idx)))])
}
let rnd = Int(arc4random_uniform(UInt32(idx + 1)))
นี้แก้ได้ด้วย นอกจากนี้ในปีงบประมาณคุณมักวนซ้ำจากarr.count - 1
ลงไปเป็น1
(หรือถ้าทำซ้ำจาก0
ถึงarr.count - 1
คุณเลือกดัชนีเช่นเนทแสดงในคำตอบที่ยอมรับ) ดูส่วนอัลกอริทึมสมัยใหม่ของการสนทนา Fisher-Yates
ทำงาน !! สิ่งมีชีวิตคืออาร์เรย์ที่จะสับเปลี่ยน
extension Array
{
/** Randomizes the order of an array's elements. */
mutating func shuffle()
{
for _ in 0..<10
{
sort { (_,_) in arc4random() < arc4random() }
}
}
}
var organisms = [
"ant", "bacteria", "cougar",
"dog", "elephant", "firefly",
"goat", "hedgehog", "iguana"]
print("Original: \(organisms)")
organisms.shuffle()
print("Shuffled: \(organisms)")
ในสวิฟท์ 4.2มีตอนนี้เป็นวิธีการทั้งจำทั้งที่ไม่แน่นอนshuffle
และไม่เปลี่ยนรูป shuffled
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการสุ่มรุ่นและอาเรย์สิ่งที่นี่
นี่คือวิธีการสับเปลี่ยนแถวลำดับหนึ่งด้วยเมล็ดพันธุ์ใน Swift 3.0
extension MutableCollection where Indices.Iterator.Element == Index {
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled , unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
srand48(seedNumber)
let number:Int = numericCast(unshuffledCount)
let r = floor(drand48() * Double(number))
let d: IndexDistance = numericCast(Int(r))
guard d != 0 else { continue }
let i = index(firstUnshuffled, offsetBy: d)
swap(&self[firstUnshuffled], &self[i])
}
}
}
let shuffl = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: arrayObject)
นี่คือสิ่งที่ฉันใช้:
import GameplayKit
extension Collection {
func shuffled() -> [Iterator.Element] {
let shuffledArray = (self as? NSArray)?.shuffled()
let outputArray = shuffledArray as? [Iterator.Element]
return outputArray ?? []
}
mutating func shuffle() {
if let selfShuffled = self.shuffled() as? Self {
self = selfShuffled
}
}
}
// Usage example:
var numbers = [1,2,3,4,5]
numbers.shuffle()
print(numbers) // output example: [2, 3, 5, 4, 1]
print([10, "hi", 9.0].shuffled()) // output example: [hi, 10, 9]
ตัวอย่างง่ายๆ:
extension Array {
mutating func shuffled() {
for _ in self {
// generate random indexes that will be swapped
var (a, b) = (Int(arc4random_uniform(UInt32(self.count - 1))), Int(arc4random_uniform(UInt32(self.count - 1))))
if a == b { // if the same indexes are generated swap the first and last
a = 0
b = self.count - 1
}
swap(&self[a], &self[b])
}
}
}
var array = [1,2,3,4,5,6,7,8,9,10]
array.shuffled()
print(array) // [9, 8, 3, 5, 7, 6, 4, 2, 1, 10]
คำตอบยอดนิยมเลิกใช้แล้วดังนั้นฉันจึงใช้เวลากับตัวเองในการสร้างส่วนขยายของตัวเองเพื่อสับเปลี่ยนอาร์เรย์ใน Swift, Swift 4.1 (Xcode 9) เวอร์ชั่นใหม่ล่าสุด:
extension Array {
// Non-mutating shuffle
var shuffled : Array {
let totalCount : Int = self.count
var shuffledArray : Array = []
var count : Int = totalCount
var tempArray : Array = self
for _ in 0..<totalCount {
let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
let randomElement : Element = tempArray.remove(at: randomIndex)
shuffledArray.append(randomElement)
count -= 1
}
return shuffledArray
}
// Mutating shuffle
mutating func shuffle() {
let totalCount : Int = self.count
var shuffledArray : Array = []
var count : Int = totalCount
var tempArray : Array = self
for _ in 0..<totalCount {
let randomIndex : Int = Int(arc4random_uniform(UInt32(count)))
let randomElement : Element = tempArray.remove(at: randomIndex)
shuffledArray.append(randomElement)
count -= 1
}
self = shuffledArray
}
}
[Array] -> [Array]
:let array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
print(array.shuffled)
สิ่งนี้จะพิมพ์array
ตามลำดับแบบสุ่ม
[Array] = [Array]
:var array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
array.shuffle()
// The array has now been mutated and contains all of its initial
// values, but in a randomized shuffled order
print(array)
สิ่งนี้พิมพ์array
ตามลำดับปัจจุบันซึ่งมีการสับแบบสุ่มแล้ว
หวังว่ามันจะใช้ได้ผลกับทุกคนหากคุณมีคำถามข้อเสนอแนะหรือความคิดเห็นโปรดถาม!
ใน SWIFT 4
func createShuffledSequenceOfNumbers(max:UInt)->[UInt] {
var array:[UInt]! = []
var myArray:[UInt]! = []
for i in 1...max {
myArray.append(i)
}
for i in 1...max {
array.append(i)
}
var tempArray:[Int]! = []
for index in 0...(myArray.count - 1) {
var isNotFinded:Bool = true
while(isNotFinded){
let randomNumber = arc4random_uniform(UInt32(myArray.count))
let randomIndex = Int(randomNumber)
if(!tempArray.contains(randomIndex)){
tempArray.append(randomIndex)
array[randomIndex] = myArray[index]
isNotFinded = false
}
}
}
return array
}
หากคุณต้องการใช้ฟังก์ชั่นวนรอบ Swift For แบบง่ายให้ใช้สิ่งนี้ ->
var arrayItems = ["A1", "B2", "C3", "D4", "E5", "F6", "G7", "H8", "X9", "Y10", "Z11"]
var shuffledArray = [String]()
for i in 0..<arrayItems.count
{
let randomObject = Int(arc4random_uniform(UInt32(items.count)))
shuffledArray.append(items[randomObject])
items.remove(at: randomObject)
}
print(shuffledArray)
Swift Array ใช้นามสกุล ->
extension Array {
// Order Randomize
mutating func shuffle() {
for _ in 0..<count {
sort { (_,_) in arc4random() < arc4random() }
}
}
}
ตั้งแต่ Swift 4.2 มีฟังก์ชั่นที่ใช้งานง่ายสองอย่าง:
// shuffles the array in place
myArray.shuffle()
และ
// generates a new array with shuffled elements of the old array
let newArray = myArray.shuffled()
นี่คือรหัสบางส่วนที่ทำงานในสนามเด็กเล่น คุณไม่จำเป็นต้องนำเข้าดาร์วินในโครงการ Xcode จริง
import darwin
var a = [1,2,3,4,5,6,7]
func shuffle<ItemType>(item1: ItemType, item2: ItemType) -> Bool {
return drand48() > 0.5
}
sort(a, shuffle)
println(a)
drand48()
ให้ตัวเลขสุ่มหลอกเดียวกันทุกครั้งเว้นแต่ว่าคุณจะตั้งค่าเมล็ดด้วยเช่นsrand48(Int(arc4random()))
มันหยุดที่ "swap (& self [i], & self [j])" เมื่อฉันอัพเกรดรุ่น xCode เป็น 7.4 beta
ข้อผิดพลาดร้ายแรง: ไม่สนับสนุนการสลับตำแหน่งด้วยตัวเอง
ฉันพบเหตุผลที่ i = j (ฟังก์ชั่นการสลับจะเกิดการระเบิด)
ดังนั้นฉันจึงเพิ่มเงื่อนไขดังนี้
if (i != j){
swap(&list[i], &list[j])
}
YA! มันโอเคสำหรับฉัน.