Consejos para jugar al golf en Swift

24

¿Cuáles son algunos consejos para jugar golf en código en Swift? Su enfoque en la seguridad parece dificultar el golf, pero eso hace pequeños consejos e incluso más útiles. ¿Hay alguna característica en Swift que pueda ayudarlo a sobresalir en code-golf en ciertas aplicaciones?

Por favor, publique un consejo por respuesta.

Addison
fuente
11
Puede contar con nosotros: si está destinado a ser seguro, se hará d̶a̶n̶g̶e̶r̶o̶u̶s̶ golfy!
Conor O'Brien
99
Esperemos que algunos buenos consejos lleguen rápidamente.
DJMcMayhem
44
Golf rápido? Pensé que se suponía que el golf era un juego lento y tranquilo ...
Jojodmo

Respuestas:

6

Rangos

Una cosa que es realmente útil es crear rangos usando el ...o..< operadores

Por ejemplo

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

Entonces, para obtener los valores segundo a cuarto de una matriz

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

Uso práctico

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

Utilizando

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

Es 8 bytes más corto que

for n in 0...3{let v=a[n];print(v)}
Jojodmo
fuente
44
... for n in 0...3{print(a[n])}no es válido?
Julian Wolf
4

Cierres:

El uso de variables que sostienen una función vs. el uso de una función en sí misma puede ayudar:

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

Pequeña diferencia aquí, pero mostrará más en algunos rompecabezas.

Funciones de acortamiento:

Mirar el ejemplo anterior me recuerda algo. A veces, si va a utilizar una función suficientes veces, vale la pena cambiarle el nombre:

Esta:

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

A esto:

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

O, en realidad, esto es mejor:

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

De esa manera solo llamas en r("Hello World",8)lugar deString(repeating:"Hello World",count:8)

Dejando de lado las declaraciones de tipo:

Una vez creé un cierre sin establecer el tipo de argumento, creando así una respuesta más corta:

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

El compilador dedujo que iestá enInt .

Cree matrices de manera rápida:

Si necesita una matriz de Ints, use a Rangepara crearla:

Array(0...5)

Esto hace lo mismo que:

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

Matrices en lugar de IfoSwitch :

En lugar de hacer esto:

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

Probablemente puedas hacer esto:

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

Acortar tipos:

Si usa mucho la conversión de tipos, es posible que desee crear un alias de tipo:

typealias f=Float

Mapa:

Recuerde que a menudo no necesita usar la returnpalabra clave enmap función.

Ejecutando Swift Online:

¡Aunque Try It Online no es compatible con Swift It ahora !

Caleb Kleveter
fuente
2
Gracias por la publicacion. Me ayudo mucho. tio.run/nexus ahora funciona con swift :)
palme
3

try

En Swift 2.xy versiones posteriores, las funciones que tradicionalmente manejaban errores al pasar un puntero a un NSErrorobjeto como parámetro de función ahorathrow su error.

Esto significa que esto:

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

ahora se ve así:

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

Esto se puede acortar usando try?o try!. try?evaluará la expresión nilsi se produce un error. try!bloqueará su programa si se produce un error, y solo debe usarse en casos en los que nunca se generará un error.

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

try?y try!guarde al menos 13 bytes del do-try-catchbucle. Tenga en cuenta que también guarda al menos un byte más pasando una matriz vacía ( []) para las opciones en lugar de niltambién.

JAL
fuente
3

Matrices reductoras

La iteración a for-in loopstravés de una matriz para obtener un valor único, como la suma de los elementos dentro, o el producto de sus elementos, puede ser demasiado largo para lo simple que es en realidad. Puedes usar el reduce()método. Algunos ejemplos:

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

Sumando los elementos en una matriz con for-inbucles:

var sum = 0

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

se puede simplificar a:

print(array.reduce(0, +))

Y obtener el producto de los elementos dentro de la matriz con bucles for-in:

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

también se puede reducir a:

print(array.reduce(1, *))
Sr. Xcoder
fuente
¿No pierdes más bytes al declarar la **función de lo que lo harías simplemente llamando powmanualmente?
JAL
@JAL sí, pero si llama a pow 10 veces, ahorra una pequeña cantidad de bytes. No es realmente la mejor técnica de golf, pero es solo otra ayuda potencial. No estaba destinado específicamente a pow, sino a otras operaciones como la búsqueda de números primos, si lo hace 3 veces, ahorra una gran cantidad de bytes
Sr. Xcoder,
2

El operador ternario de Swift es muy conciso: condition ? action : other acción

Si la condición es verdadera, haga una cosa, si no, haga otra.

textColor = bgIsBlack ? .white : .black

Esto hace que el textColorblanco sea el fondo negro o el negro si el fondo es de otro color.

El operador de fusión nula es aún más terser: a ?? b

Supongamos que está comprobando JSON para una determinada clave para que pueda presentar el valor de la clave como texto de título. Si la clave no está presente (es decir, el valor es nulo), queremos dar el texto predeterminado del título.

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

Enumeración

Puede encadenar forEachdesde enumerated()un tipo de colección para obtener una referencia al objeto (o tipo de valor) en una colección, así como su índice:

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

o

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

o ( CountableClosedRangesintaxis aún más corta )

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

Huellas dactilares:

0 1
1 2
2 3
3 4
4 5
JAL
fuente
2

Subcadena

A veces, puede guardar bytes recurriendo a los tipos de Foundation en lugar de utilizar tipos puros de Swift. Compare el acceso a una subcadena de un tipo de NSStringvs Swift String:

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

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

Incluso con los 9 caracteres perdidos al declarar xcomo un NSString, ahorras 25 más usando el tipo Foundation, ya que substringToIndextoma un Intcomo parámetro para NSStringvs vs Indexstruct ( String.CharacterView.Index) para los Stringtipos Swift .

Debo señalar que la disponibilidad de los tipos de Foundation puede diferir en varias plataformas (OS X, Linux, etc.). La mayoría de las clases de Foundation están NSUnimplementeden la versión de código abierto de Swift.

JAL
fuente
2

.mapa()

La combinación .map()con la sintaxis de cierre posterior puede ajustar los bucles for. Podemos poner las cosas que queremos iterar en una matriz, luego usar.map() para realizar alguna acción en cada elemento.

Por ejemplo, podemos usar .map()para escribir esa vieja castaña, Fizzbuzz, en una línea.

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

Fuera del golf, .map()puede ayudar a reducir la repetición. Por ejemplo, suponga que tiene una vista que necesita posicionar mediante programación. Puede colocar los anclajes para la vista en una matriz anónima y ejecutarla .map()para establecer cada restricción .isActiveen verdadero, de esta manera:

_ = [
        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
fuente
1
¿No es mejor usarlo forEachen tu segundo ejemplo? maprealmente debería usarse para transformar el contenido de una matriz, y no como un acceso directo de iteración. En este caso, estás descartando el resultado.
JAL
1

Asignaciones variables de golf en estructuras de control de flujo usando tuplas

Considere que desea usar un whilebucle y desea usar lo mismo tanto en la condición como en el bloque a seguir. Entonces, una asignación en línea en una tupla probablemente ayudaría. ¡Cuanto más largo sea tu atributo, mejor! Considere esto (3 bytes más cortos):

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

Más allá de esto:

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

Observe la (i=k.count,i>0).1 parte, que es bastante interesante.


Inspirado por una de las respuestas de Herman Lauenstein .

Sr. Xcoder
fuente
1

Cuerdas repetidas

Desafortunadamente, Swift no admite la multiplicación de cadenas con *Python. Un buen método que puede usar en su lugar es String(repeating:count:), pero desafortunadamente no es realmente golfista. Compare estos dos enfoques:

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

y

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

El segundo es un par de bytes más corto, pero eso no se puede usar en un cierre ... Mejor aún, y también funciona en cierres:

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

¿Y si lo hago varias veces? Bueno, puedes usarString.init() . Ahora, esto puede ahorrar muchos bytes. Por ejemplo (68 bytes):

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

en lugar de (74 bytes):

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

o (70 bytes):

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

Pero asegúrese de que su cadena sea lo suficientemente larga. Si está usando String(repeating:"abc",3), es mucho mejor usarlo "abcabcabc"en su lugar.

Sr. Xcoder
fuente
+1 porque no tenía idea de que las variables podrían ser inicializadores como ese.
Daniel
1

Importar

Puede reemplazar import Foundationcon import UIKit5 bytes más cortos, ya que UIKit ya importa Foundation.

Coeur
fuente
1
Ah tienes razon. No vi eso en la revisión
mbomb007