在Swift中将类型字符数组转换为字符串的最佳方法是什么?

时间:2016-06-30 17:15:48

标签: ios swift

这个问题具体是关于将Character类型的Array转换为String。将字符串数组或数字转换为字符串不是此处讨论的主题。

在以下两行中,我希望将myStringFromArray设置为" C,a,t!,"

    var myChars: [Character] = ["C", "a", "t", "!", ""]
    let myStringFromArray = myChars.joinWithSeparator(",");

但是,我无法执行该代码,因为编译器抱怨对成员joinWithSeparator"的模糊引用。

所以,有两个问题:

1)Apple说,

  

" Swift的Character类型的每个实例代表一个扩展   字形集群。扩展的字形簇是一个或一个序列   更多的Unicode标量(组合时)生成单个标量   人类可读的角色。"

对我来说听起来至少是同质的,认为实现joinWithSeparator方法来支持Character类型是合理的。那么,有没有人有一个很好的答案,为什么他们不这样做?

2)在Swift中将Character类型数组转换为字符串的最佳方法是什么?

注意:如果您不想在字符之间使用分隔符,则解决方案为:

let myStringFromArray = String(myChars) 

这会给你" Cat!"

3 个答案:

答案 0 :(得分:5)

  

对我来说,听起来至少是同质的,认为实现joinWithSeparator方法来支持Character类型是合理的。那么,有没有人对他们为什么不这样做有一个很好的答案?

这可能是对设计的疏忽。发生此错误是因为joinWithSeparator(_:)有两种可能的候选者。我怀疑这种歧义是存在的,因为Swift可以隐含地将双引号解释为StringCharacter。在这种情况下,选择哪一个是模棱两可的。

  1. 第一位候选人是joinWithSeparator(_: String) -> String。它可以满足您的需求。

    如果将分隔符视为String,则会挑选此候选人,结果为:"C,a,t,!,"

  2. 第二个是joinWithSeparator<Separator : SequenceType where Separator.Generator.Element == Generator.Element.Generator.Element>(_: Separator) -> JoinSequence<Self>。它呼叫Sequence SequenceSequence作为分隔符。方法签名有点令人满意,所以让我们分解它。此函数的参数是Separator类型。此Separator被约束为SequenceType,其中序列(Seperator.Generator.Element)的元素必须与此序列序列(Generator.Element.Generator.Element)的元素具有相同的类型。

    复杂约束的关键是确保Sequence保持同质。例如,您无法将Int的序列与Double的序列连接起来。

    如果将分隔符视为Character,则会挑选此候选对象,结果为:["C", ",", "a", ",", "t", ",", "!", ",", ""]

  3. 编译器会抛出错误以确保您意识到存在歧义。否则,程序的行为可能与您预期的不同。

    您可以通过明确地将每个Character变为String来消除这种情况的歧义。由于String SequenceType,因此不再可能出现#2候选人。

    var myChars: [Character] = ["C", "a", "t", "!", ""]
    var anotherVar = myChars.map(String.init).joinWithSeparator(",")
    
    print(anotherVar) //C,a,t,!,
    

答案 1 :(得分:3)

这个答案假设是Swift 2.2。

var myChars: [Character] = ["C", "a", "t", "!", ""]
var myStrings = myChars.map({String($0)})
var result = myStrings.joinWithSeparator(",")

joinWithSeparator仅适用于String数组:

extension SequenceType where Generator.Element == String {
    /// Interpose the `separator` between elements of `self`, then concatenate
    /// the result.  For example:
    ///
    ///     ["foo", "bar", "baz"].joinWithSeparator("-|-") // "foo-|-bar-|-baz"
    @warn_unused_result
    public func joinWithSeparator(separator: String) -> String
}

您可以创建新的扩展程序以支持字符:

extension SequenceType where Generator.Element == Character {

    @warn_unused_result
    public func joinWithSeparator(separator: String) -> String {

        var str = ""

        self.enumerate().forEach({
            str.append($1)

            if let arr = self as? [Character], endIndex: Int = arr.endIndex {
                if $0 < endIndex - 1 {
                    str.append(Character(separator))
                }
            }
        })

        return str
    }
}

var myChars: [Character] = ["C", "a", "t", "!", ""]
let charStr = myChars.joinWithSeparator(",") // "C,a,t,!,"

关于Code Review.SE的相关讨论。

答案 2 :(得分:0)

上下文:Swift3(测试版)

TL; DR高飞解决方案

var myChars:[Character] = ["C", "a", "t", "!", ""]
let separators = repeatElement(Character("-"), count: myChars.count)
let zipped = zip(myChars, separators).lazy.flatMap { [$0, $1] }
let joined = String(zipped.dropLast())

<强>博览会

行。这让我疯了。部分是因为我陷入了join语义。连接方法非常有用,但是当你背离它非常具体(但很常见)的字符串连接情况时,它会同时做两件事。它用原始序列拼接其他元素,然后将2个深字符数组(字符串数组)展平为一个单独的数组(字符串)。

OP在阵列中使用单个字符将我的大脑发送到其他地方。上面给出的答案是获得所需内容的最简单方法。将单个字符转换为单个字符串,然后使用join方法。

如果你想分别考虑这两个部分......我们从原始输入开始:

var input:[Character] = ["C", "a", "t", "!", ""]

在我们用分隔符拼接我们的字符之前,我们需要一个分隔符集合。在这种情况下,我们想要一个一次又一次重复的伪集合,而不必实际使用那么多元素创建任何数组:

let separators = repeatElement(Character(","), count: myChars.count)

这将返回一个Repeated对象(奇怪的是,您无法使用常规init方法进行实例化。)

现在我们想用分隔符拼接/编织原始输入:

let zipped = zip(myChars, separators).lazy.flatMap { [$0, $1] }

zip函数返回Zip2Sequence(奇怪的是必须通过自由函数而不是直接对象引用来实例化)。本身,当枚举时,Zip2Sequence只枚举(eachSequence1, eachSequence2)的配对元组。 flatMap表达式将其转换为两个序列中的一系列交替元素。

对于大型输入,这将创建一个较大的中间序列,只是很快就会丢弃。所以我们在那里插入了lazy访问器,它允许只在需要时计算变换,因为我们正在从中访问元素(想想迭代器)。

最后,我们知道我们可以从任何类型的Character序列中创建一个String。所以我们直接将它传递给String创建。我们添加一个dropLast()以避免添加最后一个逗号。

let joined = String(zipped.dropLast())

以这种方式分解它的有价值的东西(它肯定更多的代码行,所以最好有一个兑换价值),是我们可以深入了解我们可以用来解决类似问题的一些工具join,但不完全相同。SELECT COUNT(*) as sold_tickets FROM reservations r left join tickets t ON t.reservation_id = r.id WHERE date(r.date) = '2016-06-30' 。例如,假设我们想要尾随逗号?加入并不是答案。假设我们想要一个非常量的分隔符?只是重做第二行。等...