Header Ads Widget

Ticker

6/recent/ticker-posts

Explicar los iteradores de Swift

 Hay muy poca orientación actualizada sobre cómo hacer generadores en Swift (o iteradores , como aparentemente se les llama en Swift), especialmente si es nuevo en el idioma. ¿Por qué hay tantos tipos de generadores como AnyIteratorUnfoldSequence¿Por qué no funciona el siguiente código, que debería generarse a partir de una secuencia de Ints individuales o matrices de Ints?

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21
func chain(_ segments: Any...) -> AnyIterator<Int>{
    return AnyIterator<Int> {
        for segment in segments {
            switch segment {
            case let segment as Int:
                return segment
            case let segment as [Int]:
                for i in segment {
                    return i
                }
            default:
                return nil
            }
        }
        return nil
    }
}
let G = chain(array1, 42, array2)
while let g = G.next() {
    print(g)
}

Según tengo entendido, AnyIteratorse supone que debe tomar el cierre en el {}s y convertirlo en el .next()método en el generador devuelto, pero parece que no funciona. O debería usar UnfoldSequencelike en esta pregunta en su lugar. Estoy muy confundido.

,

Sí, el next()método de AnyIteratorllama al cierre dado.
Y en su código, ese cierre devuelve el mismo primer elemento en cada llamada, porque no recuerda qué elementos ya se han devuelto.

Si Swift tuviera una yielddeclaración como Python o C#, entonces las cosas serían más fáciles: podría yield segmentyield iy ya está.

¿Pero desafortunadamente? – Swift no tiene yielddeclaración, lo que significa
que el cierre debe administrar explícitamente algún estado para reanudar la iteración
con el siguiente elemento en cada llamada.

Una posibilidad sería mantener dos índices, uno para
el segmento actual y otro para el elemento actual dentro de
un segmento si es una matriz:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25
func chain(_ segments: Any...) -> AnyIterator<Int> {
    var currentSegment = 0 // index of current segment
    var currentElement = 0 // index of current element within current segment
    return AnyIterator<Int> {
        while currentSegment < segments.count {
            let next = segments[currentSegment]
            switch next {
            case let value as Int:
                currentSegment += 1
                return value
            case let segment as [Int]:
                if currentElement < segment.count {
                    let val = segment[currentElement]
                    currentElement += 1
                    return val
                }
                currentSegment += 1
                currentElement = 0
            default:
                return nil
            }
        }
        return nil
    }
}

Esto se puede generalizar a matrices arbitrariamente anidadas:

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19
func chain(_ segments: Any...) -> AnyIterator<Int> {
    var stack: [(Any, Int)] = [(segments, 0)]
    return AnyIterator<Int> {
        while let (next, idx) = stack.popLast() {
            switch next {
            case let value as Int:
                return value
            case let segments as [Any]:
                if idx < segments.count {
                    stack.append((segments, idx + 1))
                    stack.append((segments[idx], 0))
                }
            default:
                return nil
            }
        }
        return nil
    }
}

Las matrices que aún deben procesarse están en la pila junto con
su índice actual. Las matrices en sí no se modifican,
por lo que la copia es barata.

Ejemplo:

1 
2 
3 
4 
5
let G = chain([1, 2, [3]], 4, [5, 6, [], 7])
while let g = G.next() {
    print(g)
}
// 1 2 3 4 5 6 7

Consulte también Implementación de un generador recursivo para una estructura de árbol simple en Swift para obtener más
enfoques para enumerar recursivamente una estructura similar a un árbol.

,

También puede consultar esta implementación personalizada de un iterador como se ve en https://codeutlity.org/a/67215766/5867877

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38
class ArrayIterator<T>{
private var array : [T] = []
private var stepSize: Int = 10
private var head: Int = 0
var hasNext: Bool {
    get {
        return head < array.count
    }
}
class func from(array: [T], stepSize size: Int = 10, startingAt startIndex: Int = 0) -> ArrayIterator<T>{
    
    let a = ArrayIterator<T>()
    a.array = array
    a.stepSize = size
    a.head = startIndex
    return a
}
func next() -> Array<T>? {
    guard head < array.count else {
        return nil
    }
    
    defer {
        head = head + stepSize
    }
    
    guard stepSize < array.count else {
        return array
    }
    
    if let _ = array[safe: (head + stepSize - 1)] {
        return Array(array[head..<head + stepSize])
        
    } else {
        let remaider = (head + stepSize - 1) % array.count
        return Array(array[head..<(head + stepSize - 1 - remaider)])
    }
}

Publicar un comentario

0 Comentarios