Conseils pour jouer au golf à Swift

24

Quels sont les conseils pour jouer au golf à code dans Swift? Son accent sur la sécurité semble rendre difficile le golf, mais cela rend les petits conseils et encore plus utiles. Y a-t-il des fonctionnalités dans Swift qui peuvent l'aider à exceller dans le code-golf dans certaines applications?

Veuillez poster un pourboire par réponse.

addison
la source
11
Vous pouvez compter sur nous - si cela est censé être sûr, il sera fait d̶a̶n̶g̶e̶r̶o̶u̶s̶ golfy!
Conor O'Brien
9
Espérons que de bons conseils arriveront rapidement.
DJMcMayhem
4
Golf rapide? Je pensais que le golf était censé être un jeu calme et lent ...
Jojodmo

Réponses:

6

Gammes

Une chose qui est vraiment utile est de créer des plages à l'aide des opérateurs ...ou..<

Par exemple

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

Donc, pour obtenir les 2e à 4e valeurs d'un tableau

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

Utilisation pratique

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

En utilisant

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

8 octets de moins que

for n in 0...3{let v=a[n];print(v)}
Jojodmo
la source
4
for n in 0...3{print(a[n])}N'est pas valide?
Julian Wolf
4

Fermetures:

L'utilisation de variables qui détiennent une fonction par rapport à l'utilisation d'une fonction elle-même peut aider:

65 octets:

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

66 octets:

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

Petite différence ici, mais cela apparaîtra plus dans certains puzzles.

Fonctions de raccourcissement:

Regarder l'exemple précédent me rappelle quelque chose. Parfois, si vous utilisez une fonction suffisamment de fois, cela vaut la peine de la renommer:

Cette:

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

Pour ça:

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

Ou, en fait, c'est mieux:

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

De cette façon, vous appelez simplement r("Hello World",8)au lieu deString(repeating:"Hello World",count:8)

Laissant de côté les déclarations de type:

Une fois, j'ai créé une fermeture sans définir le type d'argument, créant ainsi une réponse plus courte:

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

Le compilateur déduit qui se itrouve dansInt .

Créez des tableaux rapidement:

Si vous avez besoin d'un tableau de Ints, utilisez a Rangepour le créer:

Array(0...5)

Cela fait la même chose que:

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

Tableaux au lieu de Ifou Switch:

Au lieu de faire ceci:

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

Vous pouvez probablement faire ceci:

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

Raccourcir les types:

Si vous utilisez beaucoup la conversion de type, vous souhaiterez peut-être créer un alias de type:

typealias f=Float

Carte:

N'oubliez pas que vous n'avez souvent pas besoin d'utiliser le returnmot - clé dans la mapfonction.

Exécuter Swift en ligne:

Bien que Try It Online ne prenne pas en charge Swift, il le fait maintenant !

Caleb Kleveter
la source
2
Merci pour le post. Cela m'a beaucoup aidé. tio.run/nexus fonctionne maintenant avec swift :)
palme
3

try

Dans Swift 2.x et versions ultérieures, les fonctions qui géraient traditionnellement les erreurs en passant un pointeur sur un NSErrorobjet en tant que paramètre de fonction deviennent désormais throwleur erreur.

Cela signifie que ceci:

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

ressemble maintenant à:

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

Cela peut être raccourci en utilisant try?ou try!. try?évaluera l'expression nilsi une erreur est levée. try!plantera votre programme si une erreur est levée et ne doit être utilisé que dans les cas où il n'y aura jamais d'erreur levée.

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

try?et try!enregistrez au moins 13 octets de la do-try-catchboucle. Notez que vous enregistrez également au moins un octet supplémentaire en passant un tableau vide ( []) pour les options au lieu de nil.

JAL
la source
3

Réduction des tableaux

Itérer avec à for-in loopstravers un tableau pour obtenir une valeur unique telle que la somme des éléments à l'intérieur, ou le produit de ses éléments peut être trop long pour sa simplicité. Vous pouvez simplement utiliser la reduce()méthode. Quelques exemples:

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

Ajout des éléments dans un tableau avec des for-inboucles:

var sum = 0

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

peut être simplifié pour:

print(array.reduce(0, +))

Et obtenir le produit des éléments à l'intérieur du tableau avec des boucles for-in:

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

peut également être réduit à:

print(array.reduce(1, *))
M. Xcoder
la source
Ne perdez-vous pas plus d'octets en déclarant la **fonction que vous le feriez en appelant simplement powmanuellement?
JAL
@JAL oui, mais si vous appelez pow 10 fois, cela économise une petite quantité d'octets. Pas vraiment la meilleure technique de golf, mais c'est juste une autre aide potentielle. Il n'était pas destiné à pow spécifiquement, mais pour d'autres opérations telles que la recherche de nombres premiers, si vous faites cela 3 fois, cela économise une énorme quantité d'octets
M. Xcoder
2

L'opérateur ternaire de Swift est très concis: condition ? action : otheraction

Si la condition est vraie, faites une chose, sinon faites autre chose.

textColor = bgIsBlack ? .white : .black

Cela rend le textColorblanc si l'arrière-plan est noir, ou noir si l'arrière-plan est d'une autre couleur.

L'opérateur de coalescence nul est encore plus terser: a ?? b

Supposons que vous vérifiez JSON pour une certaine clé afin de pouvoir présenter la valeur de la clé sous forme de texte de titre. Si la clé n'est pas présente (c'est-à-dire que la valeur est nulle), nous voulons donner le texte par défaut du titre.

title = keysValue ?? "Not Available"
Martyav
la source
2

Énumération

Vous pouvez chaîner à forEachpartir enumerated()d'un type de collection pour obtenir une référence à l'objet (ou type de valeur) dans une collection, ainsi qu'à son index:

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

ou

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

ou ( CountableClosedRangesyntaxe encore plus courte )

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

Tirages:

0 1
1 2
2 3
3 4
4 5
JAL
la source
2

Sous-chaîne

Parfois, vous pouvez enregistrer des octets en retombant sur les types Foundation au lieu d'utiliser des types Swift purs. Comparez l'accès à une sous-chaîne de type NSStringvs un Stringtype Swift :

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

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

Même avec les 9 caractères perdus en déclarant xcomme un NSString, vous économisez 25 de plus en utilisant le type Foundation, car substringToIndexprend un Intcomme paramètre pour NSString, contre un Indexstruct ( String.CharacterView.Index) pour les Stringtypes Swift .

Je dois noter que la disponibilité des types de Fondation peut différer sur plusieurs plates-formes (OS X, Linux, etc.). La plupart des classes Foundation sont NSUnimplementeddans la version open-source de Swift.

JAL
la source
2

.carte()

La combinaison .map()avec la syntaxe de fermeture finale peut resserrer les boucles for. Nous pouvons mettre les choses que nous voulons itérer dans un tableau, puis utiliser.map() pour effectuer une action sur chaque élément.

Par exemple, nous pouvons utiliser .map()pour écrire ce vieux châtaignier, Fizzbuzz, sur une seule ligne.

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

En dehors du golf, .map()peut aider à réduire les répétitions. Par exemple, supposons que vous ayez une vue que vous devez positionner par programme. Vous pouvez placer les ancres de la vue dans un tableau anonyme et les exécuter .map()pour définir chaque contrainte .isActivesur true, comme suit:

_ = [
        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
la source
1
N'est-il pas préférable d'utiliser forEachdans votre deuxième exemple? mapdevrait vraiment être utilisé pour transformer le contenu d'un tableau, et non comme raccourci d'itération. Dans ce cas, vous rejetez le résultat.
JAL
1

Affectations de variables de golf dans les structures de flux de contrôle à l'aide de tuples

Considérez que vous voulez utiliser une whileboucle et que vous voulez utiliser la même chose à la fois dans la condition et dans le bloc à suivre. Ensuite, une affectation en ligne dans un tuple serait très probablement utile. Plus votre attribut est long, mieux c'est! Considérez ceci (3 octets plus court):

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

sur ceci:

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

Remarquez la (i=k.count,i>0).1partie, qui est assez intéressante.


Inspiré par l'une des réponses d' Herman Lauenstein .

M. Xcoder
la source
1

Répétition de chaînes

Malheureusement, Swift ne prend pas en charge la multiplication de chaînes avec *, de même que Python. Une bonne méthode que vous pouvez utiliser à la place est String(repeating:count:), mais malheureusement ce n'est pas vraiment du golf. Comparez ces deux approches:

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

et

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

Le second est de quelques octets plus court, mais cela ne peut pas être utilisé dans une fermeture ... Mieux encore, et cela fonctionne également dans les fermetures:

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

Et si je le fais plusieurs fois? Eh bien, vous pouvez utiliserString.init() . Maintenant, cela peut économiser beaucoup d'octets. Par exemple (68 octets):

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

au lieu de (74 octets):

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

ou (70 octets):

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

Mais assurez-vous que votre chaîne est suffisamment longue. Si vous utilisez String(repeating:"abc",3), il est bien préférable d'utiliser à la "abcabcabc"place.

M. Xcoder
la source
+1 parce que je n'avais aucune idée que les variables pouvaient être des initialiseurs comme ça.
Daniel
1

Importation

Vous pouvez le remplacer import Foundationpar import UIKit5 octets plus court, car UIKit importe déjà Foundation.

Cœur
la source
1
Ah tu as raison. Je n'ai pas vu ça dans la revue
mbomb007