2016-06-15 5 views
25

아래 함수를 swift 3으로 변환하려면 어떻게해야합니까? 현재 Binary operator '..<' cannot be applied to operands of type 'Int' and 'Self.IndexDistance' 오류가 발생했습니다.셔플 배열 swift 3

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 } 

    for i in 0..<count - 1 { //error takes place here 
     let j = Int(arc4random_uniform(UInt32(count - i))) + i 
     guard i != j else { continue } 
     swap(&self[i], &self[j]) 
    } 
    } 
} 

참조 : https://stackoverflow.com/a/24029847/5222077

+0

에 https : // 유래합니다.com/a/27261991/2303865 –

+0

[Swift에서 배열을 임의로 섞는 방법] (https://stackoverflow.com/questions/24026510/how-do-i-shuffle-an-array-in-swift)) –

+0

Swift 3에 대한 참조가 업데이트되었으므로이 질문은 더 이상 사용되지 않습니다. –

답변

75

count가있는 IndexDistance를 반환 유형이 거리를 설명 두 컬렉션 인덱스 사이. IndexDistance이 인 것이 요구되고, Int 일 필요는없고, 은 Index과 다를 수있다. 따라서 범위 0..<count - 1을 으로 만들 수 없습니다.

용액 startIndexendIndex 대신 0count을 사용하는 것이다

extension MutableCollection where Index == Int { 
    /// Shuffle the elements of `self` in-place. 
    mutating func shuffle() { 
     // empty and single-element collections don't shuffle 
     if count < 2 { return } 

     for i in startIndex ..< endIndex - 1 { 
      let j = Int(arc4random_uniform(UInt32(endIndex - i))) + i 
      if i != j { 
       swap(&self[i], &self[j]) 
      } 
     } 
    } 
} 

다른 이점이 또한 어레이 슬라이스가 올바르게 작동하는지이다 (첫 번째 요소의 인덱스가 필요없는 경우에는 제로).

extension Collection { 
    /// Return a copy of `self` with its elements shuffled 
    func shuffled() -> [Iterator.Element] { 
     var list = Array(self) 
     list.shuffle() 
     return list 
    } 
} 

업데이트 : 새로운 "Swift API Design Guidelines"에 따른 shuffle() 배열을 반환 비 돌연변이 대응하는 돌연변이 셔플 방법 및 shuffled()에 대해 "적절한"이름

참고 그 사이에 Swift 3 버전이 How do I shuffle an array in Swift?에 추가되었습니다 (훨씬 더 일반적인).


스위프트 4 (엑스 코드 9) 들어 하나의 컬렉션의 swapAt() 메소드를 호출하여 swap() 함수 호출을 대체한다. 은 또한 Index 유형에 대한 제한이 더 이상 필요하지 않습니다 :

extension MutableCollection { 
    /// Shuffle the elements of `self` in-place. 
    mutating func shuffle() { 
     // empty and single-element collections don't shuffle 
     if count < 2 { return } 

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

자세한 내용에 대한 swapAt에 대한 SE-0173 Add MutableCollection.swapAt(_:_:)를 참조하십시오.

+3

천재입니다 –

+0

'let j'의 '+ i'가 '+ startIndex'가되어야한다고 지적해야합니다. 그렇지 않으면 인덱스가 범위를 벗어날 가능성이 매우 높습니다. –

+0

@ BjarkeH.Søndergaard : 나는 위의 코드가 정확하다는 것을 확신하며 배열과 배열 조각 모두를 테스트했습니다. 'i'는'startIndex .. = i> = startIndex'가된다. 및'j

6

단순히 배열을 셔플 대신 일반적으로 컬렉션이 확장하려고 제안 :

extension Array { 
    mutating func shuffle() { 
     for i in (0..<self.count).reversed() { 
      let ix1 = i 
      let ix2 = Int(arc4random_uniform(UInt32(i+1))) 
      (self[ix1], self[ix2]) = (self[ix2], self[ix1]) 
     } 
    } 
} 
9

피셔 예이츠가 Gamekit에 셔플있다 :

import GameKit 
let unshuffledArray = [1,2,3,4] 
let shuffledArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: unshuffledArray) 
print(shuffledArray) 
당신은 또한에 전달하고, 임의의 씨앗을 저장하면 때마다 의사 셔플 값의 순서를 얻을 수 있도록 같은 종자를 제공 할 수 있습니다

시뮬레이션을 재현해야하는 경우.

import GameKit 
let unshuffledArray = [1,2,3,4] 
let randomSource = GKLinearCongruentialRandomSource(seed: 1) 
let shuffledArray = randomSource.arrayByShufflingObjects(in: unshuffledArray) 
//Always [1,4,2,3] 
print(shuffledArray) 
+0

또한 여기에서 관찰 : http://stackoverflow.com/a/30858350/1187415 :) –

0

이에 대한 GameplayKit 프레임 워크에서 NSArray를 확장 사용할 수 있습니다

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]