Is there a way to shuffle an array so that no two consecutive values are the same?

前端 未结 4 885
醉梦人生
醉梦人生 2020-12-29 10:51

I have an array of colors that will populate a pie chart to act as a game spinner. I don\'t want the same colors to appear next to each other, making one huge chunk in the c

4条回答
  •  感动是毒
    2020-12-29 11:16

    Despite appearances, this is non-trivial. As the commentator @antonio081014 points out, it's actually an algorithmic question, and (as @MartinR points out) is addressed here. Here's a very simple heuristic that (unlike the solution from @appzYourLife) is not an algorithm, but will work in most cases, and is much faster (O(n^2) rather than O(n!)). For randomness, simply shuffle the input array first:

    func unSort(_ a: [String]) -> [String] {
        // construct a measure of "blockiness"
        func blockiness(_ a: [String]) -> Int {
            var bl = 0
            for i in 0 ..< a.count {
                // Wrap around, as OP wants this on a circle
                if a[i] == a[(i + 1) % a.count] { bl += 1 } 
            }
            return bl
        }
        var aCopy = a // Make it a mutable var
        var giveUpAfter = aCopy.count // Frankly, arbitrary... 
        while (blockiness(aCopy) > 0) && (giveUpAfter > 0) {
            // i.e. we give up if either blockiness has been removed ( == 0)
            // OR if we have made too many changes without solving
    
            // Look for adjacent pairs    
            for i in 0 ..< aCopy.count {
                // Wrap around, as OP wants this on a circle
                let prev = (i - 1 >= 0) ? i - 1 : i - 1 + aCopy.count
                if aCopy[i] == aCopy[prev] { // two adjacent elements match
                    let next = (i + 1) % aCopy.count // again, circular 
                    // move the known match away, swapping it with the "unknown" next element
                    (aCopy[i], aCopy[next]) = (aCopy[next], aCopy[i])
                }
            }
            giveUpAfter -= 1
        }
        return aCopy
    }
    
    var colors = ["blue", "red", "green", "red", "blue", "blue", "blue", "green"]
    unSort(colors) // ["blue", "green", "blue", "red", "blue", "green", "blue", "red"]
    
    // Add an extra blue to make it impossible...
    colors = ["blue", "blue", "green", "red", "blue", "blue", "blue", "green"]
    unSort(colors) //["blue", "green", "blue", "red", "blue", "blue", "green", "blue"]
    

提交回复
热议问题