How to split an array in half in Swift?

前端 未结 5 1756
醉梦人生
醉梦人生 2021-02-06 23:26

How do I split a deck of cards? I have an array made and a random card dealer, but have no idea how to split the deck.

Thanks everyone for the help! I now have a working

相关标签:
5条回答
  • 2021-02-07 00:07

    You can create an extension on SequenceType, and create a function named divide.

    This function would iterate through the elements of the sequence while placing those that match the predicate into one array (slice) and those that do not match into another array (remainder).

    The function returns a tuple containing the slice and the remainder.

    extension SequenceType {
    
        /**
         Returns a tuple with 2 arrays.
         The first array (the slice) contains the elements of self that match the predicate.
         The second array (the remainder) contains the elements of self that do not match the predicate.
         */
        func divide(@noescape predicate: (Self.Generator.Element) -> Bool) -> (slice: [Self.Generator.Element], remainder: [Self.Generator.Element]) {
            var slice:     [Self.Generator.Element] = []
            var remainder: [Self.Generator.Element] = []
            forEach {
                switch predicate($0) {
                case true  : slice.append($0)
                case false : remainder.append($0)
                }
            }
            return (slice, remainder)
        }
    
    }
    

    This is an example

    let tuple = [1, 2, 3, 4, 5].divide({ $0 >= 3 })
    tuple.slice     // [3, 4, 5]
    tuple.remainder // [1, 2]
    
    0 讨论(0)
  • 2021-02-07 00:17

    You can use subscript range

    let deck: [String] = ["J", "Q", "K", "A"]
    
    // use ArraySlice only for transient computation
    let leftSplit: ArraySlice<String> = deck[0 ..< deck.count / 2] // "J", "Q"
    let rightSplit: ArraySlice<String> = deck[deck.count / 2 ..< deck.count] // "K", "A"
    
    // make arrays from ArraySlice
    let leftDeck: [String] = Array(leftSplit) // "J", "Q"
    let rightDeck: [String] = Array(rightSplit) // "K", "A"
    

    EDIT: above code is for Swift 2, maybe for Swift 3 is a more convenient way.

    0 讨论(0)
  • 2021-02-07 00:26

    You can make an extension so it can return an array of two arrays, working with Ints, Strings, etc:

    extension Array {
        func split() -> [[Element]] {
            let ct = self.count
            let half = ct / 2
            let leftSplit = self[0 ..< half]
            let rightSplit = self[half ..< ct]
            return [Array(leftSplit), Array(rightSplit)]
        }
    }
    
    let deck = ["J", "Q", "K", "A"]
    let nums = [0, 1, 2, 3, 4]
    
    deck.split() // [["J", "Q"], ["K", "A"]]
    nums.split() // [[0, 1], [2, 3, 4]]
    

    But returning a named tuple is even better, because it enforces the fact that you expect exactly two arrays as a result:

    extension Array {
        func split() -> (left: [Element], right: [Element]) {
            let ct = self.count
            let half = ct / 2
            let leftSplit = self[0 ..< half]
            let rightSplit = self[half ..< ct]
            return (left: Array(leftSplit), right: Array(rightSplit))
        }
    }
    
    let deck = ["J", "Q", "K", "A"]
    
    let splitDeck = deck.split()
    print(splitDeck.left) // ["J", "Q"]
    print(splitDeck.right) // ["K", "A"]
    

    Note: credits goes to Andrei and Qbyte for giving the first correct answer, I'm just adding info.

    0 讨论(0)
  • 2021-02-07 00:26

    And one more realization of previously provided ideas. Firstly, up to Swift current documentation, it is better to choose names in past simple tense for functions that produce some result and present tense for mutating ones. As second, as for me, it is better to choose half adding count % 2 to give more uniformed result.

    Here is it:

    extension Array {
        func splitted() -> ([Element], [Element]) {
            let half = count / 2 + count % 2
            let head = self[0..<half]
            let tail = self[half..<count]
    
            return (Array(head), Array(tail))
        }
    }
    

    And results:

    let set1 = [1, 2, 3, 4, 5, 6, 7,8]
    let set2 = [1, 2, 3, 4, 5]
    let set3 = [1]
    let set4 = [Int]()
    
    print(set1.splitted())
    print(set2.splitted())
    print(set3.splitted())
    print(set4.splitted())
    
    ([1, 2, 3, 4], [5, 6, 7, 8])
    ([1, 2, 3], [4, 5])
    ([1], [])
    ([], [])
    
    0 讨论(0)
  • 2021-02-07 00:33

    Swift

    More generic solution to split the array into chunks the answer from this link

    extension Array {
        func chunked(into size: Int) -> [[Element]] {
            return stride(from: 0, to: count, by: size).map {
                Array(self[$0 ..< Swift.min($0 + size, count)])
            }
        }
    }
    let numbers = Array(1...100)
    let result = numbers.chunked(into: 5)
    
    0 讨论(0)
提交回复
热议问题