2016-10-16 2 views
2

... oder wie kann ich den Index innerhalb der for-Schleife Bedingung verwendenExpress for-Schleifen in swift mit Dynamikbereich

Hey Leute Da wir für Schleifen in schnellen 3 ohne c-Stil verließ ich kann‘ Es scheint so zu sein, dass Sie einen Weg finden, etwas komplizierter für Schleifen auszudrücken, also können Sie mir vielleicht helfen.

Wenn ich das

for(int i=5; num/i > 0; i*=5) 

in swift 3 schreiben würde, wie würde ich das tun?

Das schließt ich kam war:

for i in stride(from: 5, through: num, by: 5) where num/i > 0 

aber dies wird natürlich Iterierte 5 Stücke zu einem Zeitpunkt statt, wenn ich zu sein: 5, 25, 125 usw.

Irgendwelche Ideen?

Dank

+1

Wenn wir über Integer sprechen, ist 'num/i> 0 'nicht dasselbe wie das Schreiben von' num> i'? – Sulthan

+0

@Sulthan Nein, bedenke 'num = 5' &' i = 5', sowie 'num = 5' &' i = -5' – Hamish

+0

und du musst immer noch i im for loop Zustand verwenden – alex

Antwort

4

eine Hilfsfunktion verwenden (ursprünglich Converting a C-style for loop that uses division for the step to Swift 3 definiert)

public func sequence<T>(first: T, while condition: @escaping (T)-> Bool, next: @escaping (T) -> T) -> UnfoldSequence<T, T> { 
    let nextState = { (state: inout T) -> T? in 
     // Return `nil` if condition is no longer satisfied: 
     guard condition(state) else { return nil } 
     // Update current value _after_ returning from this call: 
     defer { state = next(state) } 
     // Return current value: 
     return state 
    } 
    return sequence(state: first, next: nextState) 
} 

Sie die Schleife als

let num = 1000 
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) { 
    print(i) 
} 

Eine einfachere Lösung wäre eine while-Schleife schreiben:

var i = 5 
while num/i > 0 { 
    print(i) 
    i *= 5 
} 

aber der Vorteil der ersten Lösung besteht darin, dass der Umfang der Schleifenvariable auf den Schleifenkörper beschränkt ist und dass die Schleifenvariable eine Konstante ist.

Swift 3.1 liefert ein prefix(while:) method for sequences, und dann wird die Hilfsfunktion nicht mehr erforderlich ist:

let num = 1000 
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) { 
    print(i) 
} 

Alle obigen Lösungen sind "äquivalent" auf den C-Schleife gegeben. jedoch sie alle können abstürzen, wenn num-Int.max und $0 * 5 überläuft der Nähe ist. Wenn das ein Problem ist, müssen Sie überprüfen, wenn $0 * 5 in den Ganzzahlbereich vor die Multiplikation passt.

Eigentlich macht, dass die Schleife einfacher - zumindest, wenn wir davon ausgehen, dass num >= 5 so dass die Schleife mindestens einmal ausgeführt wird:

for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) { 
    print(i) 
} 
+0

Als schrecklich Alternative (scheußlich, sogar ohne das Fehlen von 'Double' zu' Int' Grenzen) zu der Hilfefunktion oben, bis zu Swift 3.1, könnte man auch 'sequence (first: 5, next: {$ 0 * 5}) verwenden (log (Double (num))/log (5))) ';) – dfri

+0

@dfri: ... und mögliche Rundungsfehler. - Ich glaube wirklich, dass das bevorstehende 'Präfix (while:)' und 'drop (while:)' dieses und ähnliche Probleme gut lösen wird. –

+0

In der Tat. Witze beiseite, "Reihenfolge (zuerst: 5, nächstes: {num/$ 0> 0? $ 0 * 5: nil}). DropLast()' sollte eine gültige Alternative sein und die 'Optional'-Rückgabe des' next nutzen 'closure in' Sequenz (erstes: T, nächstes: T -> T?) '. – dfri

1

Der Vollständigkeit halber: eine Alternative zum while Schleife Ansatz wird mit Hilfe eines AnyIterator :

let num = 1000 

var i = 5 
for i in AnyIterator<Int>({ 
    return i <= num ? { defer { i *= 5 }; return i }() : nil 
}) { 
    // note that we choose to shadow the external i variable name, 
    // such that any access to i within this loop will only refer 
    // to the loop local immutable variable i. 
    print(i) 

    // e.g. i += 1 not legal, i refers to a constant here! 

} /* 5 
    25 
    125 
    625 */ 

Dieses Verfahren dadurch aus dem gleichen Nachteile wie die while Schleife leidet die Schleife „extern“ i Variable bleibt außerhalb und nach dem Umfang des Schleifenblocks bestehen.Diese externe i Variable ist jedoch nicht die i Variable, auf die innerhalb des Schleifenkörpers zugegriffen werden kann, da wir die Schleifenkörpervariable i den externen schattieren lassen und den Zugriff auf i innerhalb des Körpers auf den unveränderlichen, temporären (lokalen Schleifenbereich) beschränken. ein.

+0

Beachten Sie, dass dies die Schleifenvariable einmal zu oft aktualisiert (d. H. Selbst wenn "Null" zurückgegeben wird). Dies könnte in dieser Anwendung zu einem Integer-Überlauf führen und in anderen Anwendungsfällen (z. B. beim Durchlaufen einer verknüpften Liste) problematisch sein. –

+0

@MartinR Ach ja, ich bemerkte die zusätzliche Zunahme meiner Antwort, aber ich erkannte nicht die möglichen Gefahren, die damit verbunden waren. Aktualisiert mit einer Version mindestens analog zur 'while' Schleife, w.r.t. der Wert des externen 'i' nach der Schleifenvervollständigung. Vielen Dank! – dfri