Golftipps in Swift

24

Was sind einige Tipps für Code-Golf in Swift? Sein Fokus auf Sicherheit scheint es schwierig zu machen, darin zu golfen, aber das macht kleine Tipps und noch nützlicher. Gibt es irgendwelche Funktionen in Swift, die dazu beitragen können, dass Swift in bestimmten Anwendungen eine herausragende Leistung im Codegolf erbringt?

Bitte posten Sie einen Tipp pro Antwort.

addison
quelle
11
Sie können sich auf uns verlassen - wenn es sicher sein soll, wird es d̶a̶n̶g̶e̶r̶o̶u̶s̶ golfy gemacht!
Conor O'Brien
9
Hoffentlich kommen schnell ein paar gute Tipps.
DJMcMayhem
4
Schnelles Golfen? Ich dachte, Golf sollte ein langsames, ruhiges Spiel sein ...
Jojodmo

Antworten:

6

Bereiche

Eine Sache, die wirklich hilfreich ist, ist das Erstellen von Bereichen mit den Operatoren ...oder..<

Beispielsweise

array[0..<n] //first n elements of array
array[k..<n] //kth through nth elements of array
array[k...n] //kth through n-1 elements of array

So erhalten Sie die 2. bis 4. Werte eines Arrays

let myArray = ["ab", "cd", "ef", "gh", "ij", "kl", "mn", "op"]
print(myArray[1..<4]) //["cd", "ef", "gh"]

Praktischer Nutzen

let a = [3, 1, 4, 1, 5, 9]

Verwenden

for v in a[0...3]{print(v)}

Ist 8 Bytes kürzer als

for n in 0...3{let v=a[n];print(v)}
Jojodmo
quelle
4
… Ist for n in 0...3{print(a[n])}nicht gültig?
Julian Wolf
4

Verschlüsse:

Die Verwendung von Variablen, die eine Funktion enthalten, im Vergleich zur Verwendung einer Funktion selbst kann helfen:

65 Bytes:

var r:(String,Int)->String={return String(repeating:$0,count:$1)}

66 Bytes:

func r(s:String,i:Int)->String{return String(repeating:s,count:i)}

Kleiner Unterschied hier, aber es wird in einigen Rätseln mehr zeigen.

Kürzungsfunktionen:

Ein Blick auf das vorherige Beispiel erinnert mich an etwas. Wenn Sie eine Funktion oft genug verwenden, lohnt es sich manchmal, sie umzubenennen:

Dies:

String(repeating:$0,count:$1)

Dazu:

var r:(String,Int)->String={return String(repeating:$0,count:$1)}

Oder eigentlich ist das besser:

var r=String.init(repeating:count:)

Auf diese Weise rufen Sie einfach an r("Hello World",8)anstattString(repeating:"Hello World",count:8)

Typdeklarationen weglassen:

Ich habe einmal einen Abschluss erstellt, ohne den Argumenttyp festzulegen, wodurch eine kürzere Antwort erstellt wurde:

var f={(i)->Int in i-1+i%2*2}

Der Compiler hat abgeleitet, dass iin Int.

Erstellen Sie Arrays auf schnelle Weise:

Wenn Sie ein Array von benötigen Ints, verwenden Sie a Range, um es zu erstellen:

Array(0...5)

Das macht dasselbe wie:

[0,1,2,3,4,5]

Arrays anstelle von Ifoder Switch:

Anstatt dies zu tun:

if n==0{return "a"}else if n==1{return "b"}else{return "c"}

Sie können dies wahrscheinlich tun:

return ["a","b","c"][n]

Typen kürzen:

Wenn Sie die Typkonvertierung häufig verwenden, möchten Sie möglicherweise einen Typalias erstellen:

typealias f=Float

Karte:

Denken Sie daran, dass Sie das returnSchlüsselwort in der mapFunktion häufig nicht verwenden müssen .

Swift Online ausführen:

Obwohl Try It Online Swift It jetzt nicht unterstützt !

Caleb Kleveter
quelle
2
Danke für den Beitrag. Hat mir viel geholfen. tio.run/nexus funktioniert jetzt mit swift :)
palme
3

try

In Swift 2.x und höher haben Funktionen, die traditionell Fehler behandelt haben, indem ein Zeiger auf ein NSErrorObjekt als Funktionsparameter übergeben wurde, nun throwihren Fehler.

Dies bedeutet, dass dies:

var regex = NSRegularExpression(pattern: "\"((http)s?://.*?)\"", options: nil, error: nil)

sieht jetzt so aus:

do {
    let regex = try NSRegularExpression(pattern: "\"((http)s?://.*?)\"", options: [])
} catch {
    print(error)
}

Dies kann mit try?oder verkürzt werden try!. try?wertet den Ausdruck aus, nilwenn ein Fehler ausgegeben wird. try!wird Ihr Programm zum Absturz bringen, wenn ein Fehler ausgelöst wird, und sollte nur in Fällen verwendet werden, in denen niemals ein Fehler ausgelöst wird.

let regex = try! NSRegularExpression(pattern: "\"((http)s?://.*?)\"", options: [])

try?und try!speichern Sie mindestens 13 Bytes aus der do-try-catchSchleife. Beachten Sie, dass Sie auch mindestens ein weiteres Byte speichern, indem Sie []anstelle von nilauch ein leeres Array ( ) für Optionen übergeben .

JAL
quelle
3

Arrays reduzieren

Das for-in loopsDurchlaufen eines Arrays, um einen einzelnen Wert zu erhalten, z. B. die Summe der enthaltenen Elemente oder das Produkt seiner Elemente, kann zu lang sein, als dass dies tatsächlich einfach wäre. Sie können einfach die reduce()Methode verwenden. Einige Beispiele:

var array = [1,2,3,4,5,6,7]

Addieren der Elemente in einem Array mit for-inSchleifen:

var sum = 0

for item in array{
    sum += item
}
print(sum)

kann vereinfacht werden zu:

print(array.reduce(0, +))

Und das Produkt der Elemente innerhalb des Arrays mit for-in-Schleifen erhalten:

var multiplier = 1
for item in array{
    multiplier *= item
}
print(multiplier)

kann auch reduziert werden auf:

print(array.reduce(1, *))
Mr. Xcoder
quelle
Verlieren Sie nicht mehr Bytes, wenn Sie die **Funktion deklarieren , als wenn Sie sie nur powmanuell aufrufen würden ?
JAL
@JAL ja, aber wenn Sie 10 mal pow aufrufen, wird eine kleine Menge an Bytes gespart. Nicht wirklich die beste Golftechnik, aber es ist nur eine weitere mögliche Hilfe. Es war nicht für pow spezifisch gedacht, aber für andere Operationen wie das Suchen nach Primzahlen, wenn Sie das dreimal machen, werden eine riesige Menge von Bytes gespart
Mr. Xcoder
2

Swifts ternärer Operator ist sehr knapp: condition ? action : otherAktion

Wenn die Bedingung erfüllt ist, machen Sie eine Sache, wenn nicht, machen Sie etwas anderes.

textColor = bgIsBlack ? .white : .black

Dies macht das textColorWeiß, wenn der Hintergrund schwarz ist, oder schwarz, wenn der Hintergrund eine andere Farbe hat.

Der Null-Koaleszenz-Operator ist noch enger: a ?? b

Angenommen, Sie überprüfen JSON auf einen bestimmten Schlüssel, damit Sie den Wert des Schlüssels als Titeltext darstellen können. Wenn der Schlüssel nicht vorhanden ist (dh der Wert ist null), möchten wir den Titel als Standardtext festlegen.

title = keysValue ?? "Not Available"
Martyav
quelle
2

Aufzählung

Sie können Kette forEachvon enumerated()auf einer Sammlung Typ eine Referenz auf das Objekt (oder Werttyp) in einer Sammlung zu erhalten, sowie seinen Index:

[1,2,3,4,5].enumerated().forEach{print($0,$1)}

oder

for (c,i) in [1,2,3,4,5].enumerated(){print(c,i)}

oder (noch kürzere CountableClosedRangeSyntax)

(1...5).enumerated().forEach{print($0,$1)}

Drucke:

0 1
1 2
2 3
3 4
4 5
JAL
quelle
2

Teilzeichenfolge

Manchmal können Sie Bytes sparen, indem Sie auf Foundation-Typen zurückgreifen, anstatt reine Swift-Typen zu verwenden. Vergleiche den Zugriff auf einen Teilstring eines mit NSStringeinem Swift- StringTyp:

let x:NSString = "hello world"
x.substringToIndex(5) // "hello"

let y = "hello world"
y.substringToIndex(y.startIndex.advancedBy(5)) // "hello"

Selbst wenn die 9 Zeichen durch die Deklaration xals verloren gehen NSString, sparen Sie durch die Verwendung des Foundation-Typs 25 weitere Zeichen , da für Swift- Typen substringToIndexein Intals Parameter für NSStringvs an Indexstruct ( String.CharacterView.Index) Stringverwendet wird.

Ich sollte beachten, dass die Verfügbarkeit von Foundation-Typen auf mehreren Plattformen (OS X, Linux usw.) unterschiedlich sein kann. Die meisten Foundation-Klassen sind NSUnimplementedin der Open-Source-Version von Swift.

JAL
quelle
2

.Karte()

In Kombination .map()mit der Trailing-Closure-Syntax können For-Loops verstärkt werden. Wir können die Dinge, die wir durchlaufen möchten, in ein Array einfügen und dann .map()für jedes Element eine Aktion ausführen.

Zum Beispiel können wir .map()diese alte Kastanie, Fizzbuzz, in eine Zeile schreiben.

var d: [Int] = Array(1...100)

d.map{$0%15 == 0 ? print("Fizzbuzz") : $0%3 == 0 ? print("Fizz") : $0%5 == 0 ? print("Buzz") : print($0)}

Außerhalb des Golfsports .map()können Sie Wiederholungen reduzieren. Angenommen, Sie haben eine Ansicht, die Sie programmgesteuert positionieren müssen. Sie können die Anker für die Ansicht in ein anonymes Array einfügen und darüber laufen .map()lassen, um für jede Einschränkung den Wert .isActivetrue festzulegen:

_ = [
        view.topAnchor.constraint(equalTo: view.topAnchor, constant: 40),
        view.widthAnchor.constraint(equalTo: view.widthAnchor),
        view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ].map { $0.isActive = true }
Martyav
quelle
1
Ist es nicht besser, forEachin Ihrem zweiten Beispiel zu verwenden? mapsollte wirklich zum Transformieren des Inhalts eines Arrays und nicht als Iterationsverknüpfung verwendet werden. In diesem Fall verwerfen Sie das Ergebnis.
JAL
1

Variablenzuweisungen in Kontrollflussstrukturen mit Hilfe von Tupeln ausführen

Stellen Sie sich vor, Sie möchten eine whileSchleife verwenden, und Sie möchten sowohl in der Bedingung als auch im nachfolgenden Block dasselbe verwenden. Dann würde eine Inline-Zuweisung in einem Tupel höchstwahrscheinlich helfen. Je länger dein Attribut, desto besser! Betrachten Sie dies (3 Bytes kürzer):

func f(s:[Int]){var k=s,i=0;while(i=k.count,i>0).1{print(i,i+k[i-1]);k.removeLast();}}

darüber:

func g(s:[Int]){var k=s,i=0;while k.count>0{i=k.count;print(i,i+k[i-1]);k.removeLast();}}

Beachten Sie den (i=k.count,i>0).1Teil, der ziemlich interessant ist.


Inspiriert von einer Antwort von Herman Lauenstein .

Mr. Xcoder
quelle
1

Saiten wiederholen

Leider unterstützt Swift nicht die String-Multiplikation mit *, ebenso Python. Eine gute Methode, die Sie stattdessen verwenden können, ist String(repeating:count:), aber das ist leider nicht wirklich Golf. Vergleichen Sie diese beiden Ansätze:

var a=String(repeating:"abc",count:3)

und

var a="";for _ in 0..<3{a+="abc"}

Das zweite ist ein paar Bytes kürzer, aber das kann nicht in einem Closure verwendet werden ... Besser noch, und es funktioniert auch in Closures:

(0..<3).map{_ in"abc"}.joined()

Und wenn ich es mehrmals mache? Gut können Sie verwenden String.init(). Dies kann jetzt viele Bytes sparen. Zum Beispiel (68 Bytes):

let k=String.init(repeating:count:)
print(k("abcd",9)+k("XYZxyz",9))

statt (74 Bytes):

print(String(repeating:"abcd",count:9)+String(repeating:"XYZxyz",count:9))

oder (70 Bytes):

var f={String(repeating:$0,count:$1)}
print(f("abcd",9)+f("XYZxyz",9))

Aber stellen Sie sicher, dass Ihre Zeichenfolge lang genug ist. Wenn Sie verwenden String(repeating:"abc",3), ist es viel besser, "abcabcabc"stattdessen zu verwenden .

Mr. Xcoder
quelle
+1, weil ich keine Ahnung hatte, dass Variablen solche Initialisierer sein könnten.
Daniel
1

Einführen

Sie können ersetzen import Foundationmit import UIKit5 Bytes kürzer, als UIKit Import Foundation hat bereits.

Cœur
quelle
1
Ah, du hast recht.
Hab