Swift: Swift 区间与序列:Range 和 Stride

区间就像数学中的数轴片段——从 A 到 B 的连续整数。本课带你掌握 Swift 中所有区间和序列的创建、操作和自定义方法。

1. 你将学到


2. 一个活动策划师的故事

(1) 痛点:手动生成 200 个座位的编号,Excel 都要卡死了

Charlie 在策划一场 200 人的技术大会,需要为每个座位生成编号:行号 A-T(20 行),每行 10 个座位,还要把参会者分配到座位,并生成座位表。 他最开始手动在 Excel 里拖拽填充,但每加一个 VIP 座位就要重新调整整张表: `swift let seatA1 = "A1" let seatA2 = "A2" // ...一共 200 个变量 直到第 150 个座位时 Excel 崩溃,Charlie 意识到:需要程序化生成座位编号。

(2) 区间和 Stride 的解法

`swift let rows = "ABCDEFGHIJKLMNOPQRST" let seatsPerRow = 10 for row in rows { for seat in 1...seatsPerRow { print("(row)(seat)", terminator: " ") } print() }

(3) 收益:5 小时 → 3 秒

维度 拖拽 Excel Swift 区间生成
200 个座位 5 小时 3 秒
修改座位布局 重新拖拽 10 分钟 改一个数字
定制间距座位 手动查找 stride 直接生成
出错概率 0

3. Range 和 ClosedRange

Range(半开区间 ..<)包含起始值但不包含结束值。ClosedRange(闭区间 ...)包含两端。 `mermaid graph LR A["1...5"] --> B[1] A --> C[2] A --> D[3] A --> E[4] A --> F[5] G["1..<5"] --> H[1] G --> I[2] G --> J[3] G --> K[4]

区间类型 语法 包含 示例结果
ClosedRange ...b a, a+1, ..., b 1...3 -> 1,2,3
Range ..<b a, a+1, ..., b-1 1..<3 -> 1,2
单侧区间 ... a 到无穷 数组切片 rray[2...]
单侧区间 ...b ... 到 b 数组切片 rray[...2]

(1) 创建和遍历区间

`swift // 闭区间:包含 1 到 5 let closed = 1...5 for i in closed { print(i, terminator: " ") } print() // 半开区间:包含 1 到 4 let halfOpen = 1..<5 for i in halfOpen { print(i, terminator: " ") } print() // 反向遍历 for i in (1...5).reversed() { print(i, terminator: " ") } print()

(2) 区间在数组切片中的应用

`swift let numbers = [10, 20, 30, 40, 50, 60, 70] let firstThree = numbers[0..<3] print(firstThree) let fromSecond = numbers[2...] print(fromSecond) let firstFour = numbers[...3] print(firstFour)

▶ 示例:考试评分区间判断

`swift // ============================================ // 用区间在 switch 中做评分判断 // ============================================ let scores = [95, 82, 67, 54, 43, 78, 91] for score in scores { let grade: String switch score { case 90...100: grade = "A" case 80..<90: grade = "B" case 70..<80: grade = "C" case 60..<70: grade = "D" case 0..<60: grade = "F" default: grade = "Invalid" } print("Score (score): Grade (grade)") }

输出: ext Score 95: Grade A Score 82: Grade B Score 67: Grade D Score 54: Grade F Score 43: Grade F Score 78: Grade C Score 91: Grade A


4. Stride 与自定义序列

Stride 让你可以按自定义步进值遍历,而不是每次加 1。自定义序列让你可以创建自己的遍历逻辑。 `mermaid graph TB A[Sequence] --> B["stride(from: 0, to: 10, by: 2)"] A --> C["stride(from: 10, through: 0, by: -2)"] B --> D["0, 2, 4, 6, 8"] C --> E["10, 8, 6, 4, 2, 0"]

函数 区间类型 是否包含终点 示例
stride(from:to:by:) 半开 不包含 stride(from:0, to:10, by:3) -> 0,3,6,9
stride(from:through:by:) 闭区间 包含 stride(from:0, through:10, by:3) -> 0,3,6,9

(1) Stride 基本用法

`swift // 0 到 9,步进 2 for i in stride(from: 0, to: 10, by: 2) { print(i, terminator: " ") } print() // 10 到 0,步进 -3 for i in stride(from: 10, through: 0, by: -3) { print(i, terminator: " ") } print() // 浮点数步进 for temp in stride(from: 0.0, to: 1.0, by: 0.25) { print("(Int(temp * 100))%", terminator: " ") } print()

(2) 自定义序列

`swift struct FibonacciSequence: Sequence { let count: Int func makeIterator() -> FibonacciIterator { return FibonacciIterator(count: count) } } struct FibonacciIterator: IteratorProtocol { let count: Int var current = 0 var nextValue = 1 var index = 0 mutating func next() -> Int? { guard index < count else { return nil } defer { index += 1 } let result = current current = nextValue nextValue = result + current return result } } let fib = FibonacciSequence(count: 10) for num in fib { print(num, terminator: " ") } print()

▶ 示例:温度转换表生成

`swift // ============================================ // 用 stride 生成温度转换表 // ============================================ print("Celsius\tFahrenheit") print("-----------------") for celsius in stride(from: 0.0, through: 100.0, by: 10.0) { let fahrenheit = celsius * 9 / 5 + 32 print("(Int(celsius))\t(Int(fahrenheit))") } print() print("Fahrenheit\tCelsius") print("-------------------") for f in stride(from: 212.0, through: 32.0, by: -20.0) { let c = (f - 32) * 5 / 9 print("(Int(f))\t\t(Int(c))") }

输出: ` ext Celsius Fahrenheit

0 32 10 50 20 68 ...(省略中间行) 100 212

Fahrenheit Celsius

212 100 192 88 ...(省略中间行) 32 0 `


5. zip 与序列组合

zip 将两个序列按索引配对,生成元组序列。当其中一个序列结束时,zip 自动停止。

特性 说明
输入 两个序列
输出 元组序列 (Element1, Element2)
停止条件 任一序列结束
常见用途 并行遍历、配对数据、生成序号

(1) zip 基本用法

`swift let names = ["Alice", "Bob", "Charlie", "Diana"] let scores = [88, 92, 75, 95] for (name, score) in zip(names, scores) { print("(name): (score)") } let short = ["A", "B", "C"] let long = [1, 2, 3, 4, 5] for pair in zip(short, long) { print(pair) }

(2) zip + 区间生成索引

`swift let fruits = ["Apple", "Banana", "Orange", "Grape"] for (index, fruit) in zip(1..., fruits) { print("(index). (fruit)") }

▶ 示例:座位分配系统

`swift // ============================================ // 用 zip 和区间为参会者分配座位 // ============================================ let attendees = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"] let rows = ["A", "B", "C", "D"] let seatsPerRow = 4 var allSeats: [String] = [] for row in rows { for seat in 1...seatsPerRow { allSeats.append("(row)(seat)") } } print("=== Seat Assignments ===") for (attendee, seat) in zip(attendees, allSeats) { print("(seat): (attendee)") } let vipCount = 2 let vipSeats = allSeats.prefix(vipCount) let vipAttendees = attendees.prefix(vipCount) print("\n=== VIP Section ===") for (person, seat) in zip(vipAttendees, vipSeats) { print("(seat): (person)") }

输出: ` ext === Seat Assignments === A1: Alice A2: Bob A3: Charlie A4: Diana B1: Eve B2: Frank

=== VIP Section === A1: Alice A2: Bob `


6. 完整示例:考试座位表与成绩分析系统

`swift // ============================================ // 考试座位表与成绩分析 // 综合运用 Range / Stride / zip / Sequence // ============================================ import Foundation let examRows = 5 let cols = 4 print("=== Exam Seating Chart ===") for row in 0..<examRows { let rowLabel = Character(UnicodeScalar(65 + row)!) for col in 1...cols { print("(rowLabel)(col)", terminator: "\t") } print() } let students = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack", "Kevin", "Leo", "Mia", "Noah", "Olivia", "Paul", "Quinn", "Rose", "Sam", "Tina"] let examSeats = examRows * cols let assignedIndices = stride(from: 0, to: min(students.count, examSeats), by: 1) print("\n=== Seat Assignments ===") for (index, studentIndex) in zip(assignedIndices, 0..<students.count) { let row = index / cols let col = index % cols + 1 let rowLabel = Character(UnicodeScalar(65 + row)!) print("(rowLabel)(col): (students[studentIndex])") } print("\n=== Score Report ===") var scores: [String: Int] = [:] for student in students.prefix(examSeats) { scores[student] = Int.random(in: 40...100) } let gradeRanges: [ClosedRange<Int>: String] = [ 90...100: "A", 80...89: "B", 70...79: "C", 60...69: "D", 0...59: "F" ] var gradeCount: [String: Int] = ["A": 0, "B": 0, "C": 0, "D": 0, "F": 0] for (student, score) in scores.sorted(by: { .key < .key }) { var grade = "F" for (range, g) in gradeRanges { if range.contains(score) { grade = g break } } gradeCount[grade]! += 1 print("(student): (score) -- (grade)") } print("\n=== Grade Distribution ===") for grade in ["A", "B", "C", "D", "F"] { let count = gradeCount[grade]! let bar = String(repeating: "#", count: count) print("(grade): (bar) ((count))") }

输出: ` ext === Exam Seating Chart === A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4 D1 D2 D3 D4 E1 E2 E3 E4

=== Seat Assignments === A1: Alice A2: Bob ...(省略中间行) E4: Tina

=== Score Report === Alice: 82 -- B Bob: 67 -- D ...(省略中间行)

=== Grade Distribution === A: ### (3) B: ##### (5) C: #### (4) D: ### (3) F: # (1) `


❓ 常见问题

Q ... 和 ..< 有什么区别?
A ...b 包含 b(闭区间),..<b 不包含 b(半开区间)。例如 1...3 遍历 1,2,3;1..<3 遍历 1,2。
Q 区间可以用于非整数类型吗?
A 可以。只要类型遵守 Comparable 协议,如 Double、Character:1.0...5.0 或 "a"..."z"。注意 Double 区间不能用 for-in 遍历(步进不明确)。
Q stride 的 by 参数可以是负数吗?
A 可以。负值实现递减遍历。注意 rom 和 o/through 的顺序也要调换——大的在前,小的在后。
Q zip 返回的序列长度是多少?
A 两个输入序列中较短的那个的长度。zip 在任一序列结束时停止,不会自动填充 nil。
Q 如何检查一个值是否在区间内?
A 用 contains() 方法:(1...10).contains(5) 返回 true。或者在 switch 中直接匹配:case 1...10:。
Q 数组切片 rray[2...] 会复制数组吗?
A 不会。数组切片返回的是 ArraySlice,它共享原数组的内存,不会复制。切片有自己的 index 起始偏移。

📖 小节


📝 作业

  1. 基础题: 用 1...10 打印九九乘法表的第 3 行(31 到 310),输出格式为 "3 x 1 = 3"。
  2. 进阶题: 用 stride 生成从 100 到 0 的偶数序列,步进为 -2,计算这些偶数的总和。
  3. 挑战题: 创建一个自定义序列 WeekdaySequence,从指定星期几(如 "Wed")开始,无限循环输出 ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]。用 zip 与前 14 个整数配对,打印出 "Day 1: Wed", "Day 2: Thu" ...
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏