Swift에서 배열을 섞는 방법은 무엇입니까?


305

Swift에서 배열 내 요소를 무작위 화하거나 섞는 방법은 무엇입니까? 예를 들어, 배열이 52 장의 카드로 구성된 경우 , 갑판을 섞기 위해 배열 을 섞고 싶습니다 .


2
이것은 특정 언어에 국한되지 않습니다. 셔플 링 알고리즘 만 적용하면됩니다.
Gabriele Petronella

8
@Mithrandir 사실이 아닙니다. 루비에서는 갈 것입니다 array.shuffle. 자신의 버전을 구현할 필요가 없습니다. OP가 비슷한 것을 찾고 있다고 생각합니다.
Linus Oleander

1
단, 카드 셔플을 섞기 위해 셔플 알고리즘 만 사용하지 마십시오.
njzk2

답변:


626

이 답변에서는 Swift 4.2 이상에서 빠르고 균일 한 알고리즘 (Fisher-Yates)으로 셔플하는 방법과 이전의 다양한 Swift 버전에서 동일한 기능을 추가하는 방법에 대해 자세히 설명합니다. 각 Swift 버전의 이름 및 동작은 해당 버전의 mutating 및 nonmutating 정렬 방법과 일치합니다.

스위프트 4.2 이상

shuffleshuffled스위프트 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]

스위프트 4.0과 4.1

이 확장은 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 예제와 동일한 사용법.


스위프트 3

이 확장은 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 예제와 동일한 사용법.


스위프트 2

(구식 언어 : 2018 년 7 월부터 Swift 2.x를 사용하여 iTunes Connect에 발행 할 수 없습니다)

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]

스위프트 1.2

(구식 언어 : 2018 년 7 월부터 Swift 1.x를 사용하여 iTunes Connect에 발행 할 수 없습니다)

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]

1
Swift 1.2에서 함수 버전을 원할 경우 약간의 업데이트가 필요하며 countElements교체 가 필요하므로 count이제 T.Index.Distance제약 조건이 켜져 있어야합니다 C.Index.Distance == Int. 이 버전은 작동합니다 : gist.github.com/airspeedswift/03d07a9dc86fabdc370f
대기 속도

2
이것들은 실제 출력입니다. Fisher-Yates는 소스의 편향되지 않은 임의 순열을 반환해야하므로 특정 요소가 움직일 필요는 없습니다. 이 보증은없는 요소가 이동 한 번 이상하지만, 때로는 "이동"같은 인덱스이다. 가장 간단한 경우에 대해 생각하는 것입니다 [1, 2].shuffled()반환이 될까요, 아빠 [2, 1]마다?
네이트 쿡

1
if count > 0빈 배열이 전달 될 때 "치명적 오류 : 끝 <시작으로 범위를 형성 할 수 없음"을 수신하지 못하도록 mutating array 함수의 맨 위에 추가 했습니다.
Carl Smith

3
@ 1 월 : 예, guard i != j else { continue }스왑 전에 추가 하십시오. 레이더를 제출했지만 새로운 행동은 의도적 인 것입니다.
Nate Cook

3
shuffleInPlace컬렉션 인덱스가 0에서 시작하지 않으면 (예 : 배열 슬라이스) 실제로 충돌이 발생할 수 있습니다. for i in 0..<count - 1 있어야합니다 for i in startIndex ..< endIndex - 1(그리고 스위프트 3으로의 변환은 거의 사소합니다).
Martin R

131

편집 : 다른 답변에서 언급했듯이 Swift 4.2는 최종적으로 난수 생성을 표준 라이브러리에 추가하고 배열 셔플 링을 완료했습니다.

그러나 GameplayKit 의 GKRandom/ GKRandomDistributionsuite는 여전히 새로운 RandomNumberGenerator프로토콜에 유용 할 수 있습니다. 새로운 표준 라이브러리 프로토콜을 준수하기 위해 GameplayKit RNG에 확장을 추가하면 다음 과 같은 이점을 얻을 수 있습니다.

  • 전송 가능한 RNG (테스트에 필요할 때 "임의"시퀀스를 재현 할 수 있음)
  • 속도를위한 견고성을 희생하는 RNG
  • 균일하지 않은 분포를 생성하는 RNG

... 그리고 여전히 Swift의 새로운 "원시"랜덤 API를 사용합니다.

이 답변의 나머지 부분은 RNG 및 / 또는 구형 Swift 컴파일러에서의 사용과 관련이 있습니다.


여기에 좋은 대답이 있으며 조심하지 않으면 자신의 셔플을 작성하는 것이 오류가 발생하기 쉬운 이유에 대한 좋은 예가 있습니다.

iOS 9, macOS 10.11 및 tvOS 9 이상에서는 직접 작성할 필요가 없습니다. 있다 피셔 - 예이츠의 효율적이고 정확한 구현 (이름에도 불구하고, 단지 게임이다) 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()

6
GameplayKit에서 내가 찾은 적이없는 다른 유용한 유틸리티를 찾을 수 있는지 궁금합니다.
Richard Venable

6
그래프 검색, 트리 검색, 규칙 시스템 ... 게임 디자인과 그 밖의 모든 것에 유용한 많은 것들 .
rickster 2016 년

5
Swift 3 / iOS 10에서는 다음과 같이 변경되었습니다.let shuffled = lcg.arrayByShufflingObjects(in: array)
Evan Pon

30

에서 스위프트 2.0 , GameplayKit는 구조에 올 수 있습니다! ( iOS9 이상에서 지원 )

import GameplayKit

func shuffle() {
    array = GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(array)
}

5
배열을 섞기 위해 GameplayKit을 가져 오는 것은 좋은 생각처럼 들리지 않습니다
Lope

3
왜? 그것은 시스템의 일부이며 바이너리에 추가하지 않습니다.
Abizern

3
당신은 범위도 할 수 단순히로 가져 오기import GameplayKit.GKRandomSource
JRG-개발자

26

조금 더 짧은 것이 있습니다.

sorted(a) {_, _ in arc4random() % 2 == 0}

1
@moby이 sort함수는 요소를 주문하려면 클로저가 필요합니다. 이 클로저는 두 개의 매개 변수 (elem1, elem2)를 사용하며 첫 번째 값이 두 번째 값 앞에 나타나려면 true를 반환하고 그렇지 않으면 false를 반환해야합니다. 우리가 대신 임의의 불리언을 반환하면 ... 우리는 모든 것을 섞습니다 :)
Jean Le Moignan

2
확인하거나 반증하기 위해 여기에 수학자가 있습니까?
Jean Le Moignan

9
pjs가 다른 매우 유사한 답변에 대한 응답으로 지적했듯이 결과의 균일 한 분포를 생성 하지는 않습니다 . Nate Cook의 답변에 표시된대로 Fisher-Yates Shuffle 을 사용하십시오 .

1
이것은 영리한 속임수이지만 셔플의 품질면에서 볼 수 없습니다. 하나,이 폐쇄는 arc4random_uniform()현재 모듈로 바이어스의 영향을 받기 때문에를 사용해야합니다 . 둘째, 출력은 정렬 알고리즘 (소스를 보지 않고 우리에게 알려지지 않음)에 크게 의존합니다.
Alexander-복원 자 Monica Monica

1
이 간단한 접근법을 계속하면서, 이것은 꽤 잘 작동하는 것 같습니다 : collection.sorted { _,_ in arc4random_uniform(1) == 0 }
markiv

7

촬영 네이트의 알고리즘을 나는 이것이 스위프트 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


6

필자의 경우 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
    }

}

5

이것은 스위프트 4 (Xcode 9)에 대한 네이트의 Fisher-Yates 셔플 구현 버전입니다 .

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.

3

이것이 내가 사용하는 것입니다 :

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
}

3

스위프트 4 for 루프에서 배열의 요소를 섞습니다. 여기서 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
        }
    }
}

2

@Nate Cook 답변에 따라 Swift 3 솔루션 : (지수가 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])
        }
    }
}

1
컬렉션 인덱스가 0에서 시작하면 (예 : 배열 슬라이스) 충돌이 발생할 수 있습니다. var a = [1, 2, 3, 4, 5, 6][3..<6]; a.shuffleInPlace()여러 번 달리십시오 . – 올바른 해결책 은 stackoverflow.com/a/37843901/1187415 를 참조하십시오 .
Martin R

2

이것이 가장 간단한 방법입니다. import GamplaykitVC에 연결하고 아래 코드를 사용하십시오. 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!)

}

2

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"]

배열에서 새로운 뒤섞인 배열을 얻기 위해 이전 코드를 리팩터링하고 확장 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"]

1

일반적인 swap기능을 사용 하고 언급 된 Fisher-Yates를 구현할 수 있습니다 .

for idx in 0..<arr.count {
  let rnd = Int(arc4random_uniform(UInt32(idx)))
  if rnd != idx {
    swap(&arr[idx], &arr[rnd])
  }
}

덜 장황한 :

for idx in 0..<steps.count {
  swap(&steps[idx], &steps[Int(arc4random_uniform(UInt32(idx)))])
}

2
이것은 최소한 여기에 설명 된 하나의 오류로 인해 심각한 문제 가 발생 하여 값이 항상 원래 위치에서 교체됩니다. 이 해결됩니다 . 또한, FY에서는 일반적으로 반복에서 아래로 (또는에서 당신 반복 처리를하는 경우 에는 , 당신은 허용 대답 네이트 쇼처럼 인덱스를 선택). Fisher-Yates 토론의 Modern Algorithm 섹션 을 참조하십시오 . let rnd = Int(arc4random_uniform(UInt32(idx + 1)))arr.count - 110arr.count - 1
Rob

1

공장!!. 유기체는 섞는 배열입니다.

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)")


0

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])
        }
    }
}


0

이것이 내가 사용하는 것입니다 :

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]

0

간단한 예 :

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]

0

작동하는 배열 확장 (돌연변이 및 비 돌연변이)

스위프트 4.1 / Xcode 9

최고 답변은 더 이상 사용되지 않으므로 최신 버전의 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순서는 이미 무작위로 섞인 현재 순서대로 인쇄 됩니다.


질문, 제안 또는 의견이 있으시면 언제든지 문의하십시오.


0

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
}

0

간단한 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)

확장 기능을 사용한 스위프트 어레이 셔플->

extension Array {
    // Order Randomize
    mutating func shuffle() {
        for _ in 0..<count {
            sort { (_,_) in arc4random() < arc4random() }
        }
    }
}

0

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()

-2

놀이터에서 실행되는 코드는 다음과 같습니다. 실제 Xcode 프로젝트에서 Darwin을 가져올 필요는 없습니다.

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)

7
결과가 불균일하게 분포됩니다. 또한 Fisher-Yates 셔플 은 O (n) 시간에 균일하게 분포 된 결과를 제공 하는 O (n log n) 입니다.
pjs

다음 drand48()과 같이 시드를 설정하지 않는 한 매번 동일한 의사 난수를 제공합니다.srand48(Int(arc4random()))
Kametrixom

-3

xCode 버전을 7.4 베타로 업그레이드하면 "swap (& self [i], & self [j])"에서 멈 춥니 다.
치명적인 오류 : 위치를 자체와 교체하는 것은 지원되지 않습니다

i = j 인 이유를 찾았습니다 (스왑 기능이 폭발 함)

그래서 아래와 같이 조건을 추가합니다

if (i != j){
    swap(&list[i], &list[j])
}

당신! 전 괜찮아요.


이것은 원래 질문에 대한 답변이 아니라 Chris의 답변 에 대한 의견 인 것으로 보입니다 .
Mogsdad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.