如何用String.Index生成子串键统计长度为2的子串出现次数?求更优方案
优化Swift中子串键的生成与计数方法
原问题与代码
我对String.Index并不熟悉,请问有没有比以下代码更优的方法来生成子串键?
原代码:
let a = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA" let keysize = 2 let size = a.count + 1 - keysize var counts: [String: Int] = [:] var i = 0 while i < size { let start_offset = a.index(a.startIndex, offsetBy: i) let end = a.index(start_offset, offsetBy: keysize) if let key = String( a[start_offset..<end] ) { if let v = counts[key] { counts[key] = v + 1 } else { counts[key] = 1 } } i += 1 } for (k,v) in counts { print("\(k): \(v)") }
原代码运行结果:
CC: 5 TA: 1 TG: 3 GC: 9 CG: 7 GT: 2 GA: 3 CA: 3 AC: 2 TC: 2 AG: 3 AT: 1 TT: 2 GG: 12 AA: 1 CT: 3
优化方案
方案1:简化循环与计数逻辑
通过直接遍历有效索引范围,结合字典的default下标简化计数,避免手动维护循环变量和嵌套判断:
let a = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA" let keysize = 2 var counts: [String: Int] = [:] // 遍历所有能取到keysize长度子串的起始索引 for start in a.indices.dropLast(keysize - 1) { let end = a.index(start, offsetBy: keysize) let key = String(a[start..<end]) counts[key, default: 0] += 1 } for (k, v) in counts { print("\(k): \(v)") }
优化点说明:
- 用
a.indices.dropLast(keysize - 1)自动筛选有效起始索引,无需手动计算size变量,避免索引越界风险 counts[key, default: 0] += 1直接处理计数逻辑,省去判断key是否存在的嵌套if let,代码更简洁- 直接遍历索引序列,替代手动维护
i变量的while循环,可读性更强
方案2:函数式风格实现
如果偏好函数式编程,可以用map生成所有子串,再通过reduce统计计数:
let a = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA" let keysize = 2 // 生成所有符合要求的子串 let substrings = a.indices.dropLast(keysize - 1).map { start in String(a[start..<a.index(start, offsetBy: keysize)]) } // 统计子串出现次数 let counts = substrings.reduce(into: [String: Int]()) { result, key in result[key, default: 0] += 1 } for (k, v) in counts { print("\(k): \(v)") }
优化点说明:
- 将子串生成与计数统计逻辑分离,代码结构更清晰
- 利用Swift标准库的高阶函数,减少手动循环代码,逻辑更紧凑
两种方案都能得到和原代码完全一致的输出,同时避免了手动处理String.Index的繁琐,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者igouy
相关产品推荐
相关产品推荐

