Swift: Intervalos e Sequências do Swift

Um intervalo é como um segmento em uma reta numérica — inteiros consecutivos de A até B. Esta lição aborda como criar, usar e personalizar todos os tipos de intervalo e sequência no Swift.

1. O Que Você Vai Aprender


2. Uma História Real de um Organizador de Eventos

(1) Problema: Gerar manualmente 200 números de assento — Excel travou

Charlie está organizando uma conferência de tecnologia para 200 pessoas. Ele precisa gerar números de assento: fileiras A a T (20 fileiras), 10 assentos por fileira, atribuir participantes aos assentos e produzir um mapa de lugares. Ele começou arrastando a alça de preenchimento no Excel, mas toda vez que adicionava um assento VIP, precisava reajustar toda a planilha:

SWIFT
let seatA1 = "A1"
let seatA2 = "A2"
// ... 200 variables total

No assento #150, o Excel travou. Charlie percebeu: ele precisava de geração programática de números de assento.

(2) A Solução com Range e Stride

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

(3) Resultado: 5 horas → 3 segundos

Métrica Arrastando no Excel Geração com Range no Swift
200 assentos 5 horas 3 segundos
Mudar layout dos assentos Arrastar novamente 10 minutos Mudar um número
Assentos espaçados Consulta manual stride gera diretamente
Taxa de erro Alta 0

3. Range e ClosedRange

Range (semiaberto ..<) inclui o valor inicial mas exclui o final. ClosedRange (fechado ...) inclui ambos os extremos.

100%
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]
Tipo de Intervalo Sintaxe Inclui Exemplo de Resultado
ClosedRange a...b a, a+1, ..., b 1...3 -> 1,2,3
Range a..<b a, a+1, ..., b-1 1..<3 -> 1,2
PartialFrom a... a até o infinito Fatiamento de array array[2...]
PartialThrough ...b ... até b Fatiamento de array array[...2]

(1) Criando e Percorrendo Intervalos

SWIFT
// Closed range: includes 1 through 5
let closed = 1...5
for i in closed {
    print(i, terminator: " ")
}
print()
// Half-open range: includes 1 through 4
let halfOpen = 1..<5
for i in halfOpen {
    print(i, terminator: " ")
}
print()
// Reverse traversal
for i in (1...5).reversed() {
    print(i, terminator: " ")
}
print()

(2) Intervalos no Fatiamento de Array

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)

▶ Exemplo: Classificação de Notas com Correspondência de Intervalo

SWIFT
// ============================================
// Using ranges in switch for grade classification
// ============================================
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)")
}

Saída:

TEXT 📖 Somente leitura
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 e Sequências Personalizadas

Stride permite percorrer com um valor de passo personalizado em vez de incrementar de 1 em 1. Sequências personalizadas permitem definir sua própria lógica de iteração.

100%
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"]
Função Tipo de Intervalo Extremo Inclusivo Exemplo
stride(from:to:by:) Semiaberto Não stride(from:0, to:10, by:3) -> 0,3,6,9
stride(from:through:by:) Fechado Sim stride(from:0, through:10, by:3) -> 0,3,6,9

(1) Uso Básico do Stride

SWIFT
// 0 to 9, step 2
for i in stride(from: 0, to: 10, by: 2) {
    print(i, terminator: " ")
}
print()
// 10 to 0, step -3
for i in stride(from: 10, through: 0, by: -3) {
    print(i, terminator: " ")
}
print()
// Floating-point stepping
for temp in stride(from: 0.0, to: 1.0, by: 0.25) {
    print("\(Int(temp * 100))%", terminator: " ")
}
print()

(2) Sequências Personalizadas

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()

▶ Exemplo: Gerador de Tabela de Conversão de Temperatura

SWIFT
// ============================================
// Generate temperature conversion table with 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))")
}

Saída:

TEXT 📖 Somente leitura
Celsius	Fahrenheit
-----------------
0		32
10		50
20		68
... (linhas intermediárias omitidas)
100		212

Fahrenheit	Celsius
-------------------
212		100
192		88
... (linhas intermediárias omitidas)
32		0

5. zip e Combinação de Sequências

zip emparelha duas sequências por índice, produzindo uma sequência de tuplas. Ele para automaticamente quando qualquer uma das sequências termina.

Característica Descrição
Entrada Duas sequências
Saída Sequência de tuplas (Elemento1, Elemento2)
Condição de parada A sequência que terminar primeiro
Usos comuns Percorrimento paralelo, emparelhamento de dados, geração de índices

(1) Uso Básico do 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 + Range para Geração de Índices

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

▶ Exemplo: Sistema de Atribuição de Assentos

SWIFT
// ============================================
// Assign attendees to seats using zip and ranges
// ============================================
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)")
}

Saída:

TEXT 📖 Somente leitura
=== Atribuições de Assentos ===
A1: Alice
A2: Bob
A3: Charlie
A4: Diana
B1: Eve
B2: Frank

=== Seção VIP ===
A1: Alice
A2: Bob

6. Exemplo Completo: Mapa de Assentos de Prova e Análise de Notas

SWIFT
// ============================================
// Exam seating chart and grade analysis
// Combining 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: { $0.key < $1.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))")
}

Saída:

TEXT 📖 Somente leitura
=== Mapa de Assentos da Prova ===
A1	A2	A3	A4
B1	B2	B3	B4
C1	C2	C3	C4
D1	D2	D3	D4
E1	E2	E3	E4

=== Atribuições de Assentos ===
A1: Alice
A2: Bob
... (linhas intermediárias omitidas)
E4: Tina

=== Relatório de Notas ===
Alice: 82 -- B
Bob: 67 -- D
... (linhas intermediárias omitidas)

=== Distribuição de Conceitos ===
A: ### (3)
B: ##### (5)
C: #### (4)
D: ### (3)
F: # (1)

❓ Perguntas Frequentes

P: Qual é a diferença entre ... e ..<? R: a...b inclui b (intervalo fechado). a..<b exclui b (intervalo semiaberto). Por exemplo, 1...3 percorre 1,2,3; 1..<3 percorre 1,2. P: Os intervalos podem ser usados com tipos não inteiros? R: Sim. Qualquer tipo em conformidade com Comparable funciona, como Double ou Character: 1.0...5.0 ou "a"..."z". Note que intervalos Double não podem ser usados com for-in (ambiguidade de passo). P: O parâmetro by do stride pode ser negativo? R: Sim. Um valor negativo cria um percorrimento descendente. Lembre-se de inverter a ordem de from e to/through — maior primeiro, menor depois. P: Qual é o comprimento da sequência retornada por zip? R: O comprimento da sequência de entrada mais curta. zip para quando qualquer sequência termina; ele não preenche com nil. P: Como verificar se um valor está dentro de um intervalo? R: Use o método contains(): (1...10).contains(5) retorna true. Ou corresponda em um switch: case 1...10:. P: O fatiamento de array com array[2...] copia o array? R: Não. O fatiamento de array retorna um ArraySlice que compartilha a memória do array original — nenhuma cópia é feita. O slice tem seu próprio deslocamento de índice inicial.


📖 Resumo


📝 Exercícios

  1. Iniciante: Use 1...10 para imprimir a 3ª linha de uma tabuada (31 até 310), formatada como "3 x 1 = 3".
  2. Intermediário: Use stride para gerar números pares de 100 até 0 com passo de -2 e calcule sua soma.
  3. Desafio: Crie uma sequência personalizada SequenciaDiasSemana que começa de um dia da semana dado (ex.: "Qua") e itera indefinidamente por ["Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"]. Use zip para emparelhar com os primeiros 14 inteiros e imprimir "Dia 1: Qua", "Dia 2: Qui"...
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%