17-String与Array

71 阅读5分钟

Swift String与Array

string内存分配

字符小于等于15个时候

var str1 = "0123456789" 字符串长度 <= 0XF,字符串直接存放在str1变量的内存中

字符大于15个时候

var str2 = "0123456789ABCDEFGHIJ" 字符串的地址值存放在__TEXT.cstring中(常量区)

使用append的情况
str1.appended("ABCDE")
str1.appended("F")

由于字符串长度小于 <=0XF,所以字符串内容依然存放在str1变量的内存中

String基础

String创建
// 字符串字面量
let str1 = "Hello, World!"
let str2 = "Swift"

// 空字符串
let emptyString1 = ""
let emptyString2 = String()

// 多行字符串
let multiline = """
    This is a
    multiline string
    with multiple lines
    """

// 字符串插值
let name = "Swift"
let version = 5.0
let info = "Welcome to \(name) \(version)"
字符串属性
let text = "Hello, Swift!"

// 长度
print(text.count) // 13

// 是否为空
print(text.isEmpty) // false

// 首字符和尾字符
print(text.first) // Optional("H")
print(text.last) // Optional("!")

String操作

字符串拼接
let str1 = "Hello"
let str2 = "World"

// 使用 + 操作符
let result1 = str1 + ", " + str2 + "!"

// 使用 += 操作符
var greeting = "Hello"
greeting += ", World!"

// 使用字符串插值
let result2 = "\(str1), \(str2)!"
字符串比较
let str1 = "Hello"
let str2 = "hello"
let str3 = "Hello"

// 相等比较
print(str1 == str3) // true
print(str1 == str2) // false

// 大小写不敏感比较
print(str1.lowercased() == str2.lowercased()) // true

// 前缀和后缀检查
print(str1.hasPrefix("He")) // true
print(str1.hasSuffix("lo")) // true

String索引

索引操作
let str = "Hello, Swift!"

// 开始和结束索引
let startIndex = str.startIndex
let endIndex = str.endIndex

// 偏移索引
let secondChar = str[str.index(after: startIndex)]
let thirdChar = str[str.index(startIndex, offsetBy: 2)]

// 字符范围
let range = str.index(startIndex, offsetBy: 0)...str.index(startIndex, offsetBy: 4)
let hello = str[range] // "Hello"
子字符串
let str = "Hello, Swift Programming!"

// 获取子字符串
let hello = str.prefix(5) // "Hello"
let programming = str.suffix(12) // "Programming!"

// 使用范围
let startIndex = str.index(str.startIndex, offsetBy: 7)
let endIndex = str.index(str.startIndex, offsetBy: 11)
let swift = str[startIndex..<endIndex] // "Swift"

String方法

常用方法
let text = "  Hello, Swift!  "

// 大小写转换
print(text.lowercased()) // "  hello, swift!  "
print(text.uppercased()) // "  HELLO, SWIFT!  "
print(text.capitalized) // "  Hello, Swift!  "

// 去除空白
print(text.trimmingCharacters(in: .whitespaces)) // "Hello, Swift!"

// 替换
print(text.replacingOccurrences(of: "Swift", with: "iOS")) // "  Hello, iOS!  "

// 分割
let words = text.trimmingCharacters(in: .whitespaces).components(separatedBy: " ")
print(words) // ["Hello,", "Swift!"]
高级字符串操作
let text = "Swift is awesome!"

// 包含检查
print(text.contains("Swift")) // true
print(text.contains("iOS")) // false

// 查找
if let range = text.range(of: "awesome") {
    print("Found at: \(range)")
}

// 正则表达式
let emailPattern = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let email = "test@example.com"
print(email.range(of: emailPattern, options: .regularExpression) != nil) // true

Array基础

image.png

Array创建
// 数组字面量
let numbers = [1, 2, 3, 4, 5]
let strings = ["apple", "banana", "orange"]

// 空数组
let emptyArray1: [Int] = []
let emptyArray2 = [Int]()
let emptyArray3 = Array<Int>()

// 重复元素数组
let zeros = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0]

// 范围数组
let range = Array(1...5) // [1, 2, 3, 4, 5]
Array属性
let numbers = [1, 2, 3, 4, 5]

// 数量
print(numbers.count) // 5

// 是否为空
print(numbers.isEmpty) // false

// 首元素和尾元素
print(numbers.first) // Optional(1)
print(numbers.last) // Optional(5)

// 索引范围
print(numbers.indices) // 0..<5

Array操作

添加元素
var numbers = [1, 2, 3]

// 追加单个元素
numbers.append(4)
print(numbers) // [1, 2, 3, 4]

// 追加多个元素
numbers.append(contentsOf: [5, 6, 7])
print(numbers) // [1, 2, 3, 4, 5, 6, 7]

// 插入元素
numbers.insert(0, at: 0)
print(numbers) // [0, 1, 2, 3, 4, 5, 6, 7]

// 插入多个元素
numbers.insert(contentsOf: [-2, -1], at: 0)
print(numbers) // [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]
删除元素
var numbers = [1, 2, 3, 4, 5]

// 删除指定索引元素
let removed = numbers.remove(at: 2)
print(removed) // 3
print(numbers) // [1, 2, 4, 5]

// 删除第一个元素
let first = numbers.removeFirst()
print(first) // 1
print(numbers) // [2, 4, 5]

// 删除最后一个元素
let last = numbers.removeLast()
print(last) // 5
print(numbers) // [2, 4]

// 删除所有元素
numbers.removeAll()
print(numbers) // []
修改元素
var numbers = [1, 2, 3, 4, 5]

// 修改单个元素
numbers[0] = 10
print(numbers) // [10, 2, 3, 4, 5]

// 修改范围元素
numbers[1...3] = [20, 30, 40]
print(numbers) // [10, 20, 30, 40, 5]

// 替换范围
numbers.replaceSubrange(0...1, with: [100, 200])
print(numbers) // [100, 200, 30, 40, 5]

Array方法

遍历方法
let numbers = [1, 2, 3, 4, 5]

// for-in 循环
for number in numbers {
    print(number)
}

// forEach 方法
numbers.forEach { number in
    print(number)
}

// enumerated 方法
for (index, value) in numbers.enumerated() {
    print("Index: \(index), Value: \(value)")
}
转换方法
let numbers = [1, 2, 3, 4, 5]

// map - 转换每个元素
let doubled = numbers.map { $0 * 2 }
print(doubled) // [2, 4, 6, 8, 10]

// compactMap - 过滤nil值
let strings = ["1", "2", "abc", "4", "5"]
let validNumbers = strings.compactMap { Int($0) }
print(validNumbers) // [1, 2, 4, 5]

// flatMap - 展平数组
let arrays = [[1, 2], [3, 4], [5, 6]]
let flattened = arrays.flatMap { $0 }
print(flattened) // [1, 2, 3, 4, 5, 6]
过滤和查找
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// filter - 过滤元素
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [2, 4, 6, 8, 10]

// first(where:) - 查找第一个符合条件的元素
let firstEven = numbers.first(where: { $0 % 2 == 0 })
print(firstEven) // Optional(2)

// contains - 检查是否包含元素
print(numbers.contains(5)) // true
print(numbers.contains(15)) // false

// allSatisfy - 检查所有元素是否都满足条件
print(numbers.allSatisfy { $0 > 0 }) // true
聚合方法
let numbers = [1, 2, 3, 4, 5]

// reduce - 聚合操作
let sum = numbers.reduce(0) { result, number in
    return result + number
}
print(sum) // 15

// 简化写法
let sum2 = numbers.reduce(0, +)
print(sum2) // 15

// 最大值和最小值
print(numbers.max()) // Optional(5)
print(numbers.min()) // Optional(1)

// 排序
let shuffled = [3, 1, 4, 1, 5, 9, 2, 6]
let sorted = shuffled.sorted()
print(sorted) // [1, 1, 2, 3, 4, 5, 6, 9]

let sortedDescending = shuffled.sorted(by: >)
print(sortedDescending) // [9, 6, 5, 4, 3, 2, 1, 1]

高级用法

数组分组
let words = ["apple", "banana", "apricot", "blueberry", "cherry"]

// 按首字母分组
let grouped = Dictionary(grouping: words) { $0.first! }
print(grouped)
// ["a": ["apple", "apricot"], "b": ["banana", "blueberry"], "c": ["cherry"]]
数组去重
let numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

// 使用Set去重
let uniqueNumbers = Array(Set(numbers))
print(uniqueNumbers) // [2, 3, 1, 4] (顺序可能不同)

// 保持顺序去重
let uniqueOrderedNumbers = numbers.reduce([]) { result, number in
    return result.contains(number) ? result : result + [number]
}
print(uniqueOrderedNumbers) // [1, 2, 3, 4]
数组分割
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 分割成两部分
let (evenNumbers, oddNumbers) = numbers.reduce(([], [])) { result, number in
    if number % 2 == 0 {
        return (result.0 + [number], result.1)
    } else {
        return (result.0, result.1 + [number])
    }
}
print(evenNumbers) // [2, 4, 6, 8, 10]
print(oddNumbers) // [1, 3, 5, 7, 9]

性能优化

预分配容量
// 好的做法:预分配容量
var numbers = [Int]()
numbers.reserveCapacity(1000)
for i in 0..<1000 {
    numbers.append(i)
}

// 避免:频繁扩容
var numbers2 = [Int]()
for i in 0..<1000 {
    numbers2.append(i) // 可能会多次扩容
}
使用合适的方法
let numbers = [1, 2, 3, 4, 5]

// 好的做法:使用 contains
if numbers.contains(3) {
    print("Found")
}

// 避免:使用 filter
if !numbers.filter({ $0 == 3 }).isEmpty {
    print("Found")
}

// 好的做法:使用 first(where:)
if let first = numbers.first(where: { $0 > 3 }) {
    print("Found: \(first)")
}

// 避免:使用 filter + first
if let first = numbers.filter({ $0 > 3 }).first {
    print("Found: \(first)")
}

实践示例

文本处理
func processText(_ text: String) -> [String: Any] {
    let words = text.lowercased()
        .components(separatedBy: .punctuationCharacters)
        .joined()
        .components(separatedBy: .whitespaces)
        .filter { !$0.isEmpty }
    
    let wordCount = words.count
    let uniqueWords = Set(words)
    let wordFrequency = Dictionary(grouping: words) { $0 }
        .mapValues { $0.count }
    
    return [
        "wordCount": wordCount,
        "uniqueWordCount": uniqueWords.count,
        "wordFrequency": wordFrequency
    ]
}

let text = "Hello, world! This is a test. Hello again!"
let result = processText(text)
print(result)
数据过滤和排序
struct Person {
    let name: String
    let age: Int
    let city: String
}

let people = [
    Person(name: "Alice", age: 25, city: "New York"),
    Person(name: "Bob", age: 30, city: "London"),
    Person(name: "Charlie", age: 35, city: "New York"),
    Person(name: "David", age: 28, city: "Paris")
]

// 过滤和排序
let youngPeopleInNY = people
    .filter { $0.age < 30 && $0.city == "New York" }
    .sorted { $0.age < $1.age }

print(youngPeopleInNY)
// [Person(name: "Alice", age: 25, city: "New York")]

最佳实践

1. 选择合适的数据结构
// 好的做法:频繁查找用Set
let validIds: Set = [1, 2, 3, 4, 5]
if validIds.contains(userId) {
    // 处理
}

// 避免:频繁查找用Array
let validIds = [1, 2, 3, 4, 5]
if validIds.contains(userId) {
    // 处理
}
2. 避免不必要的拷贝
// 好的做法:使用Substring
func processSubstring(_ text: String) -> String {
    let substring = text.prefix(10)
    return String(substring) // 只在需要时转换
}

// 避免:过早转换
func processSubstring(_ text: String) -> String {
    let substring = String(text.prefix(10)) // 不必要的拷贝
    return substring
}
3. 合理使用map和filter
// 好的做法:链式操作
let result = numbers
    .filter { $0 > 0 }
    .map { $0 * 2 }
    .sorted()

// 避免:多次遍历
let positive = numbers.filter { $0 > 0 }
let doubled = positive.map { $0 * 2 }
let sorted = doubled.sorted()

📝 重要提示

  1. String是值类型:修改字符串会创建新的实例
  2. String索引:不支持整数索引,需要使用String.Index
  3. Array性能:插入和删除操作的时间复杂度取决于位置
  4. 内存管理:大数组操作时注意内存使用
  5. 类型安全:Swift的类型系统保证操作的安全性

🎯 总结

String和Array是Swift中最基础和最重要的数据类型。掌握它们的用法对于Swift编程至关重要:

  • String:提供了丰富的文本处理功能
  • Array:提供了强大的集合操作能力
  • 性能考虑:选择合适的方法和数据结构
  • 类型安全:利用Swift的类型系统避免错误

通过合理使用这些特性,可以编写出高效、安全的Swift代码。


本文档基于Swift 5.0+版本,涵盖了String和Array的核心用法和最佳实践。