Swift,处理数组和数据类型(从字符串中分割字符串)
Swift,处理数组和数据类型(从字符串中分割字符串)
我几天前刚开始学习Swift,但是我对于所有不同的数据类型都感到困惑...
假设我们这样做:
var myarray = ["justin", "steve", "peter"] var newString = myarray[2]
那么为什么我现在不能仅打印出"peter"中的"p"呢?
print(newString[0])
---> 这给了我一个错误:
"'subscript' is unavailable: cannot subscript String with an Int"
在这个主题中:
[Get nth character of a string in Swift programming language
它说:
"请注意,您无法将从一个字符串创建的索引(或范围)用于另一个字符串"
但是我无法想象,没有办法处理它...
因为当我这样做时:
var myarray = ["justin", "steve", "p.e.t.e.r"] var newString = myarray[2] let a : [String] = newString.componentsSeparatedByString(".") print(a[2])
- 然后它可以工作。它打印出(在这种情况下)"t"。
那么我如何用'SeparatedByString'将其分割为“什么都没有”?
我确信解决这个问题也将帮助我解决许多其他问题。
我希望我以正确的方式提出了问题。
谢谢您的任何解决方案或提示 🙂
Swift处理数组和数据类型(从字符串中拆分字符串)
在Swift中,使用实例方法componentsSeparatedByString应用于String实例,可以得到一个String实例的数组,即[String]。数组的元素可以以经典的Java/C++方式索引(let thirdElement = array[2])。
如果您想将String实例("peter")拆分成一个由单个字符String实例组成的数组,可以利用String实例的CharacterView属性,然后将CharacterView中的每个单个字符映射回单个字符String实例。
let str = "peter"
let strArray = str.characters.map(String.init(_:)) // ["p", "e", "t", "e", "r"]
let thirdElement = strArray[2] // t
虽然这是一种迂回的方式(String -> CharacterView -> [String] -> String),但是您最好直接查看在上面提到的链接中对直接String索引的优秀回答。
上述方法可能适用于以下可能的特殊情况,正如下面的Hamish所指出的,如果您需要经常访问String中特定索引处的字符,并且希望利用数组提供的O(1)随机访问功能(如果您使用不可变的String,则更适用,因为相应的String数组只需要为每个不可变的String实例生成一次)。
如果您需要频繁访问给定索引处的字符,而无需进行线性遍历,这是一个很好的方法 🙂
感谢你。:)它给我2个错误("Expected ',' separator" "Expected expression in list of expressions"),但这可能是我的Swift版本的问题(2.1.1)。我也将检查相关链接。谢谢,帮助我不发脾气!:D
没错!我真的不知道我对.map(String.init(_:))这种变化是怎么想的,与.map { String($0) }相比,但是嘿,为什么不呢:D
将上面代码片段中的第二行替换为let strArray = str.characters.map { String($0) },它可能适用于Swift 2.1(已测试并在Swift 2.2中工作)。
是的,当你不得不用(init)和(_:)来消除歧义时,我通常会回到使用闭包表达式,但我猜这是一个个人偏好的问题 🙂
我也更喜欢闭包,因为它的语义更好,但我不确定与直接提供一个初始化函数引用相比,闭包方法是否会产生最小(/可以忽略的 🙂 额外开销。我从未对此进行过基准测试,并且编译器应该将前者优化为后者,但我不能确定。
是的,它有效!谢谢!:D
成本差异确实应该微不足道。没有优化的情况下,我会说闭包表达式实际上应该稍微更快一些。原因是String.init(_)不能直接传递给map(_) - 它首先必须部分应用于元类型String.self,这将在堆上创建一个新的闭包。另一方面,闭包表达式是静态存储的,因此不会产生分配成本。
但是通过优化,编译器可以执行各种聪明的特殊化和内联操作,所以很难推理(但从快速基准测试来看,闭包表达式仍然胜出)。
非常有教育意义,谢谢!我自己的猜测受到了太多C++的启发,认为轻量级函数指针与稍微复杂的函数对象(闭包)进行比较;非常高兴知道在Swift中不适用。顺便说一下,如果map没有,这应该没有任何区别吗?
你确实可以这样思考,只是反过来 - 在这种情况下,闭包表达式是(或多或少)轻量级的函数指针(尽管它可能携带一个堆分配的上下文对象,用于存储有关捕获值的信息,并且可能部分应用于自己的捕获内容)。另一方面,String.init(_)在这种情况下需要部分应用,因此会动态创建一个新的闭包(函数对象)来封装将(String.Type)->(Character)-> String应用于(Character)-> String。
而且map没有 😉
我明白了,感谢详细的解释!啊是的,我混淆了和尾随闭包的最终参数 🙂
不客气:)如果您有一个具有签名(Character)->String的全局函数,并将其传递给map(_)而不是String.init,那么这也可以与将简单函数指针传递给map(_)相媲美。还有一点,当将函数传递给涉及泛型的参数时,事情变得稍微复杂一些 - 它们用“重新抽象补丁助手”部分应用(我相信这是为了统一传递的函数的调用约定)。这将产生闭包分配的成本,但可以在-O构建中进行特殊化处理。
抱歉有点罗嗦 - 当你研究生成的SIL时就会发生这种情况:P
没问题:)此外,如果您对具有签名(Character)->String的函数的全局函数进行了部分应用,并将其传递给map(_),而不是String.init,那么这也可以与将简单的函数指针传递给map(_)相媲美。另外,现在我想起来了,当将函数传递给涉及泛型的参数时,情况会稍微复杂一些-它们会使用“重新抽象补丁助手”部分应用(我相信这是为了统一传递的函数的调用约定)。这会产生闭包分配的成本,但可以在-O构建中进行特殊化处理。
很抱歉有点罗嗦 - 当你研究生成的SIL时就会发生这种情况:P