如何在Swift中将数组分成两半?

35

如何分割一副扑克牌?我已经创建了一个数组和一个随机的发牌器,但不知道如何分割扑克牌。

感谢大家的帮助!现在我有一个可用的纸牌应用程序,虽然还遇到了其他问题,但它们很快得到了解决。


3
请查看此链接:http://swiftdoc.org/func/split/ - Dániel Nagy
5个回答

32

您可以创建一个扩展,使其返回一个由两个数组组成的数组,可以使用Ints、Strings等进行操作:

您可以制作一个扩展程序,使其返回一个包含两个数组的数组,可以使用整数、字符串等进行操作。

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

但是返回一个命名元组会更好,因为它强制要求你期望得到恰好两个数组作为结果:

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

注意:感谢 Andrei 和 Qbyte 给出了第一个正确答案,我只是在补充信息。


命名元组绝对是更好的选择。它让编译器强制执行你只期望两个数组。 - Asa
同意。 :) 根据您的评论,我稍微修改了我的答案措辞。 - Eric Aya

21

你可以使用下标范围

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"

编辑:上面的代码适用于Swift 2,可能有一种更方便的方式适用于Swift 3。


1
你可能想要使用单独的数组而不是 ArraySlice。因此,Array(leftSplit) 将会得到所需的结果。 - Qbyte

15

Swift

参考此链接,可得到将数组分块的更通用解决方案。

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)

1
从问题的要求来看有点误导人。这并不能真正帮助将某物一分为二。如果我指定2,那么我会得到几个大小为2的数组。如果我指定count的一半,那么当count是奇数时,我将得到一个额外的只有一个元素的数组。 - keji

6

之前提供的想法有一个新的认识。首先,根据Swift目前的文档,最好选择过去式来为生成一些结果的函数命名,选择现在时来表示会改变值得函数。其次,对我来说,最好选择将count % 2作为一半添加以获得更统一的结果。

在这里:

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

        return (Array(head), Array(tail))
    }
}

结果如下:

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.devided())
print(set2.devided())
print(set3.devided())
print(set4.devided())

([1, 2, 3, 4], [5, 6, 7, 8])
([1, 2, 3], [4, 5])
([1], [])
([], [])

2
"split" 的过去式仍然是 "split"。为了遵循您所参考的指南,最好找到一个同义词,其过去式的拼写不同。 - Marmoy

3

您可以在SequenceType上创建扩展,并创建名为divide的函数。

该函数将遍历序列的元素,同时将符合谓词的元素放入一个数组slice中,将不符合的元素放入另一个数组remainder中。

该函数返回一个包含sliceremainder的元组。

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

}

这是一个例子

let tuple = [1, 2, 3, 4, 5].divide({ $0 >= 3 })
tuple.slice     // [3, 4, 5]
tuple.remainder // [1, 2]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接