Swift 扩展归纳---Array (二)

2 阅读3分钟

接上篇 Array(一) 扩展归纳,继续记录其他常用的扩展

9、 String 数组扩展

// MARK: - String 数组扩展
extension Array where Element == String {
    
    /// 转换为字符串(用分隔符连接)
    func toString(separator: String = ", ") -> String {
        return joined(separator: separator)
    }
    
    /// 过滤空字符串
    var nonEmpty: [String] {
        return filter { !$0.isEmpty }
    }
    
    /// 过滤空白字符串
    var nonBlank: [String] {
        return filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }
    }
    
    /// 转换为小写
    var lowercased: [String] {
        return map { $0.lowercased() }
    }
    
    /// 转换为大写
    var uppercased: [String] {
        return map { $0.uppercased() }
    }
    
    /// 去除首尾空白字符
    var trimmed: [String] {
        return map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
    }
}

// 生成十六进制字符串
extension Array where Element == UInt8 {
    var hexString: String {
        return self.compactMap { String(format: "%02x", $0).uppercased() }
        .joined(separator: "")
    }
}

使用示例:

// MARK: - 1. toString - 转换为字符串
    print("=== 1. toString - 字符串连接 ===")

    let fruits = ["苹果", "香蕉", "橙子", "葡萄"]
    print("水果数组: \(fruits)")
    print("默认连接 (逗号): \(fruits.toString())")
    print("自定义分隔符 (|): \(fruits.toString(separator: " | "))")
    print("换行连接: \(fruits.toString(separator: "\n"))")

    // MARK: - 2. nonEmpty - 过滤空字符串
    print("=== 2. nonEmpty - 过滤空字符串 ===")

    let userInputs = ["张三", "", "李四", "", "王五", "", "赵六"]
    print("原始输入: \(userInputs)")
    print("过滤空字符串后: \(userInputs.nonEmpty)")
    print("有效用户数量: \(userInputs.nonEmpty.count)")
    // MARK: - 3. nonBlank - 过滤空白字符串
    print("=== 3. nonBlank - 过滤空白字符串 ===")
    let comments = ["很好用!", "   ", "推荐给朋友", "\n\n", "  ", "五星好评", "\t\t"]
    print("用户评论原始数据:")
    for (index, comment) in comments.enumerated() {
        print("  \(index + 1): '\(comment)'")
    }

    print("\n过滤空白后:")
    let validComments = comments.nonBlank
    for (index, comment) in validComments.enumerated() {
        print("  \(index + 1): '\(comment)'")
    }
    print("有效评论数: \(validComments.count)")


    // MARK: - 4. lowercased - 转换为小写
    print("=== 4. lowercased - 转换为小写 ===")

    let mixedCaseNames = ["iPhone", "MacBook", "iPad", "Apple Watch", "AirPods"]
    print("原始产品名: \(mixedCaseNames)")
    print("小写转换: \(mixedCaseNames.lowercased)")
    // MARK: - 5. uppercased - 转换为大写
    print("=== 5. uppercased - 转换为大写 ===")

    let countryNames = ["china", "usa", "japan", "germany", "france"]
    print("国家名称: \(countryNames)")
    print("大写转换: \(countryNames.uppercased)")

    // MARK: - 6. trimmed - 去除首尾空白字符
    print("=== 6. trimmed - 去除首尾空白字符 ===")
    let userNames = ["  张三  ", "\n李四\n", "\t王五\t", "   赵六   ", "孙七"]
    print("用户姓名输入:")
    for (index, name) in userNames.enumerated() {
        print("  \(index + 1): '\(name)'")
    }

    let cleanNames = userNames.trimmed
    print("\n清理后:")
    for (index, name) in cleanNames.enumerated() {
        print("  \(index + 1): '\(name)'")
    }


    // MARK: - 7. 综合应用示例
    print("=== 7. 综合应用示例 ===")
    // 标签系统
    print("\n🏷️ 文章标签系统:")
    let articleTags = ["  iOS  ", "", "  SWIFT  ", "   mobile   ", "\n\n", "  Development  ", "  "]
    print("原始标签: \(articleTags)")

    let processedTags = articleTags
        .trimmed           // 去空白
        .nonEmpty          // 去空字符串
        .lowercased        // 统一小写
        .map { $0.capitalized }  // 首字母大写

    print("处理后标签: \(processedTags)")
    print("标签字符串: #\(processedTags.toString(separator: " #"))")
    print("SEO标签: \(processedTags.lowercased.toString(separator: ", "))")

10、实用扩展

// MARK: - 实用扩展
extension Array {
    
    /// 判断数组是否为空或nil
    var isNilOrEmpty: Bool {
        return isEmpty
    }
    
    /// 安全的count(防止nil)
    var safeCount: Int {
        return count
    }
    
    /// 转换为JSON字符串(如果元素可序列化)
    func toJSONString() -> String? {
        guard JSONSerialization.isValidJSONObject(self) else { return nil }
        guard let data = try? JSONSerialization.data(withJSONObject: self, options: []) else { return nil }
        return String(data: data, encoding: .utf8)
    }
    
    /// 打印数组内容(调试用)
    func printElements() {
        for (index, element) in enumerated() {
            print("[\(index)]: \(element)")
        }
    }
    
    /// 执行每个元素的操作
    func forEach(_ body: (Element, Int) throws -> Void) rethrows {
        for (index, element) in enumerated() {
            try body(element, index)
        }
    }
    
    /// 异步处理每个元素
    @available(iOS 13.0, *)
    func asyncForEach(_ operation: @escaping (Element) async -> Void) async {
        for element in self {
            await operation(element)
        }
    }
    
    /// 条件追加元素
    mutating func appendIf(_ condition: Bool, _ element: Element) {
        if condition {
            append(element)
        }
    }
    
    /// 条件追加数组
    mutating func appendIf(_ condition: Bool, contentsOf array: [Element]) {
        if condition {
            append(contentsOf: array)
        }
    }
}

使用示例:

// MARK: - 1. isNilOrEmpty - 判断数组是否为空
    print("=== 1. isNilOrEmpty - 空数组判断 ===")

    let emptyArray: [Int] = []
    let nonEmptyArray = [1, 2, 3]
    print("空数组 \(emptyArray) 是否为空: \(emptyArray.isNilOrEmpty ? "✅" : "❌")")
    print("非空数组 \(nonEmptyArray) 是否为空: \(nonEmptyArray.isNilOrEmpty ? "❌" : "✅")")

    // MARK: - 3. toJSONString - JSON序列化
    print("=== 3. toJSONString - JSON序列化 ===")
    // 嵌套数组
    let nestedArray = [
        ["name": "张三", "age": 25],
        ["name": "李四", "age": 30]
    ]

    print("\n嵌套数组序列化:")
    if let json = nestedArray.toJSONString() {
        print("  成功: \(json)")
    } else {
        print("  失败 ❌")
    }

    // 实际应用:API数据发送
    print("\n📡 API数据发送示例:")
    let userData = [
        "用户ID": 12345,
        "用户名": "developer",
        "邮箱": "dev@example.com"
    ] as [String: Any]

    let userArray = [userData]
    if let jsonString = userArray.toJSONString() {
        print("准备发送的JSON: \(jsonString)")
        print("数据大小: \(jsonString.count) 字符")
    }
    // MARK: - 4. printElements - 调试打印
    print("=== 4. printElements - 调试打印 ===")

    let debugArray = ["启动", "加载配置", "连接数据库", "初始化完成"]
    print("应用启动流程调试:")
    debugArray.printElements()

    // MARK: - 5. forEach (带索引) - 增强遍历
    print("=== 5. forEach (带索引) - 增强遍历 ===")

    let students = ["张三", "李四", "王五", "赵六"]
    print("学生名单:")

    students.forEach { name, index in
        let number = index + 1
        print("  \(number). \(name)")
    }

    // MARK: - 6. asyncForEach - 异步处理
    let urls = [
        "https://api.github.com/users/apple",
        "https://api.github.com/users/microsoft",
        "https://api.github.com/users/google"
    ]

    print("开始处理 \(urls.count) 个URL...")

    await urls.asyncForEach { url in
        await downloadUserInfo(from: url)
    }

    print("所有网络请求完成!\n")
        
    // MARK: - 7. appendIf - 条件追加
    print("=== 7. appendIf - 条件追加 ===")

    var shoppingCart = ["苹果", "香蕉"]
    print("购物车初始状态: \(shoppingCart)")

    let hasDiscount = true
    let isVip = false

    shoppingCart.appendIf(hasDiscount, "优惠券")
    print("有折扣,添加优惠券: \(shoppingCart)")

    shoppingCart.appendIf(isVip, "VIP专享商品")
    print("非VIP,不添加专享商品: \(shoppingCart)")

    // 批量条件追加
    print("\n批量条件追加:")
    var features: [String] = ["基础功能"]

    let isPremium = true
    let isEnterprise = false

    let premiumFeatures = ["高级统计", "数据导出", "API访问"]
    let enterpriseFeatures = ["单点登录", "自定义品牌", "专属支持"]

    features.appendIf(isPremium, contentsOf: premiumFeatures)
    print("Premium用户功能: \(features)")

    features.appendIf(isEnterprise, contentsOf: enterpriseFeatures)
    print("非Enterprise用户,功能不变: \(features)")

11、搜索和过滤扩展

// MARK: - 搜索和过滤扩展
extension Array where Element: StringProtocol {
    
   /// 模糊搜索 - 检查查询字符是否按顺序出现在字符串中
    func fuzzySearch(_ query: String) -> [Element] {
        guard !query.isEmpty else { return Array(self) }
        
        let lowercaseQuery = query.lowercased()
        
        return filter { element in
            let elementString = String(element).lowercased()
            
            var queryIndex = lowercaseQuery.startIndex
            
            for char in elementString {
                if queryIndex < lowercaseQuery.endIndex &&
                   char == lowercaseQuery[queryIndex] {
                    queryIndex = lowercaseQuery.index(after: queryIndex)
                }
                
                // 如果所有查询字符都匹配了,提前退出
                if queryIndex == lowercaseQuery.endIndex {
                    break
                }
            }
            
            return queryIndex == lowercaseQuery.endIndex
        }
    }
    
    /// 按相关性排序的搜索
    func search(_ query: String) -> [Element] {
        let lowercaseQuery = query.lowercased()
        
        return self
            .filter { $0.lowercased().contains(lowercaseQuery) }
            .sorted { left, right in
                let leftLower = left.lowercased()
                let rightLower = right.lowercased()
                
                // 优先级:完全匹配 > 开头匹配 > 包含匹配
                if leftLower == lowercaseQuery { return true }
                if rightLower == lowercaseQuery { return false }
                if leftLower.hasPrefix(lowercaseQuery) && !rightLower.hasPrefix(lowercaseQuery) { return true }
                if rightLower.hasPrefix(lowercaseQuery) && !leftLower.hasPrefix(lowercaseQuery) { return false }
                
                return leftLower.count < rightLower.count
            }
    }
}

12、 性能监控扩展

// MARK: - 性能监控扩展
extension Array {
    
    /// 性能基准测试
    func benchmark<T>(
        iterations: Int = 1000,
        operation: (Array<Element>) -> T
    ) -> (averageTime: TimeInterval, results: [T]) {
        var times: [TimeInterval] = []
        var results: [T] = []
        
        for _ in 0..<iterations {
            let startTime = CFAbsoluteTimeGetCurrent()
            let result = operation(self)
            let endTime = CFAbsoluteTimeGetCurrent()
            
            times.append(endTime - startTime)
            results.append(result)
        }
        
        let averageTime = times.reduce(0, +) / TimeInterval(times.count)
        return (averageTime, results)
    }
    
    /// 内存使用情况
    var memoryFootprint: Int {
        return MemoryLayout<Element>.stride * count + MemoryLayout<Array<Element>>.size
    }
    
    /// 性能分析报告
    func performanceReport() -> String {
        let elementSize = MemoryLayout<Element>.size
        let arraySize = MemoryLayout<Array<Element>>.size
        let totalMemory = elementSize * count + arraySize
        
        return """
        Array Performance Report:
        - Element count: \(count)
        - Element size: \(elementSize) bytes
        - Array overhead: \(arraySize) bytes
        - Total memory: \(totalMemory) bytes
        - Memory per element: \(count > 0 ? totalMemory / count : 0) bytes
        """
    }
}

使用示例:

-- 性能基准测试示例
    let numbers = Array(1...10000)

    // 测试不同操作的性能
    print("数组大小: \(numbers.count) 个元素")

    // 测试求和操作
    let sumBenchmark = numbers.benchmark(iterations: 1000) { array in
        return array.reduce(0, +)
    }
    print("\n求和操作基准测试:")
    print("  平均耗时: \(String(format: "%.6f", sumBenchmark.averageTime * 1000))毫秒")
    print("  首个结果: \(sumBenchmark.results.first ?? 0)")

// MARK: -- 内存分析示例
// 不同大小的数组内存对比
    let smallArray = Array(1...100)
    let mediumArray = Array(1...1000)
    let largeArray = Array(1...10000)
    
    print("内存使用对比:")
    print("  小数组 (100元素): \(smallArray.memoryFootprint) 字节")
    print("  中数组 (1000元素): \(mediumArray.memoryFootprint) 字节")
    print("  大数组 (10000元素): \(largeArray.memoryFootprint) 字节")
    
    // 计算内存增长比例
    let smallToMedium = Double(mediumArray.memoryFootprint) / Double(smallArray.memoryFootprint)
    let mediumToLarge = Double(largeArray.memoryFootprint) / Double(mediumArray.memoryFootprint)
    
    print("\n内存增长比例:")
    print("  小→中: \(String(format: "%.1f", smallToMedium))倍")
    print("  中→大: \(String(format: "%.1f", mediumToLarge))倍")

// MARK: -- 性能分析报告示例"
    
    // 不同类型数组的性能报告
    let intArray = Array(1...5000)
    let stringArray = Array(repeating: "Hello World", count: 5000)
    
    print("Int数组性能报告:")
    print(intArray.performanceReport())
    
    print("\nString数组性能报告:")
    print(stringArray.performanceReport())
    
    
    // 性能对比分析
    print("\n🔍 性能对比分析:")
    let intMemory = intArray.memoryFootprint
    let stringMemory = stringArray.memoryFootprint
    print("  相同元素数量下的内存使用:")
    print("    Int: \(intMemory) 字节")
    print("    String: \(stringMemory) 字节 (\(String(format: "%.1f", Double(stringMemory)/Double(intMemory)))倍)")

暂时记录在这里,后续有新增的再补充吧。