Dicas para jogar golfe em Swift

24

Quais são algumas dicas para o código de golfe no Swift? Seu foco na segurança parece dificultar a prática do golfe, mas isso dá pequenas dicas e é ainda mais útil. Existem recursos no Swift que podem ajudá-lo a se destacar no code-golf em certos aplicativos?

Poste uma dica por resposta.

Addison
fonte
11
Você pode contar conosco - se for para ser seguro, será feito golfe!
Conor O'Brien
9
Esperamos que algumas boas dicas venham rapidamente.
DJMcMayhem
4
Golfe rápido? Eu pensei que o golfe era suposto ser um jogo de ritmo lento, calma ...
Jojodmo

Respostas:

6

Gamas

Uma coisa que é realmente útil é criar intervalos usando o ...ou..< operadores

Por exemplo

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

Então, para obter os valores de 2 a 4 de uma matriz

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

Uso pratico

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

Usando

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

É 8 bytes menor que

for n in 0...3{let v=a[n];print(v)}
Jojodmo
fonte
4
... for n in 0...3{print(a[n])}não é válido?
Julian Wolf
4

Encerramentos:

O uso de variáveis ​​como manter uma função vs. usar uma função em si pode ajudar:

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

Pequena diferença aqui, mas mostrará mais em alguns quebra-cabeças.

Funções de encurtamento:

Observar o exemplo anterior me lembra algo. Às vezes, se você estiver usando uma função vezes suficientes, vale a pena renomeá-la:

Este:

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

Para isso:

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

Ou, na verdade, isso é melhor:

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

Dessa forma, você acabou de ligar r("Hello World",8) vez deString(repeating:"Hello World",count:8)

Deixando de fora as declarações de tipo:

Certa vez, criei um fechamento sem definir o tipo de argumento, criando assim uma resposta mais curta:

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

O compilador inferiu que iestá emInt .

Crie matrizes da maneira rápida:

Se você precisar de uma matriz de Ints, use a Rangepara criá-la:

Array(0...5)

Isso faz o mesmo que:

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

Matrizes em vez de IfouSwitch :

Em vez de fazer isso:

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

Você provavelmente pode fazer isso:

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

Encurtar tipos:

Se você estiver usando muito a conversão de tipos, convém criar um alias de tipo:

typealias f=Float

Mapa:

Lembre-se de que muitas vezes você não precisa usar a returnpalavra - chave nomap função.

Executando o Swift Online:

Embora o Try It Online não suporte o Swift It agora !

Caleb Kleveter
fonte
2
Obrigado pelo post. Me ajudou muito. tio.run/nexus agora funciona com swift :)
palme
3

try

No Swift 2.xe acima, funções que tradicionalmente manipulavam erros passando um ponteiro para um NSErrorobjeto como um parâmetro de função agorathrow seu erro.

Isso significa que isto:

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

agora se parece com:

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

Isso pode ser reduzido usando try?ou try!. try?avaliará a expressão para nilse um erro for lançado. try!travará seu programa se um erro for lançado e deve ser usado apenas nos casos em que nunca haverá um erro.

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

try?e try!salve pelo menos 13 bytes do do-try-catchloop. Observe que você também salva pelo menos mais um byte passando uma matriz vazia ( []) para opções em vez de niltambém.

JAL
fonte
3

Reduzindo matrizes

A iteração for-in loopsatravés de uma matriz para obter um valor único, como a soma dos elementos internos ou o produto de seus elementos, pode ser muito longo para ser simples. Você pode apenas usar o reduce()método Alguns exemplos:

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

Adicionando os elementos em uma matriz com for-inloops:

var sum = 0

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

pode ser simplificado para:

print(array.reduce(0, +))

E obtendo o produto dos elementos dentro da matriz com loops de entrada:

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

também pode ser reduzido para:

print(array.reduce(1, *))
Mr. Xcoder
fonte
Você não perde mais bytes declarando a **função do que faria apenas chamando powmanualmente?
JAL
@ JAL sim, mas se você chamar pow 10 vezes, ele economizará uma pequena quantidade de bytes. Não é realmente a melhor técnica de golfe, mas é apenas outra ajuda em potencial. Ele não foi feito para pow especificamente, mas para outras operações, tais como a procura de números primos, se você fizer isso 3 vezes, ele economiza uma enorme quantidade de bytes
Mr. Xcoder
2

O operador ternário de Swift é muito conciso: condition ? action : other ação

Se a condição for verdadeira, faça uma coisa, se não, faça outra coisa.

textColor = bgIsBlack ? .white : .black

Isso torna o textColor branco se o fundo for preto ou preto se o fundo for de outra cor.

O operador coalescente nulo é ainda mais tenso: a ?? b

Digamos que você esteja verificando o JSON para uma determinada chave para poder apresentar o valor da chave como texto do título. Se a chave não estiver presente (ou seja, o valor for nulo), queremos fornecer o texto padrão do título.

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

Enumeração

Você pode fazer a cadeia forEachde enumerated()um tipo de coleção para obter uma referência ao objeto (ou tipo de valor) em uma coleção, bem como seu índice:

[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 ( CountableClosedRangesintaxe ainda mais curta )

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

Impressões:

0 1
1 2
2 3
3 4
4 5
JAL
fonte
2

Substring

Às vezes, você pode salvar bytes recorrendo aos tipos Foundation em vez de usar tipos Swift puros. Compare o acesso a uma substring de um tipo NSStringSwift vs String:

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

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

Mesmo com os 9 caracteres perdidos ao declarar xcomo um NSString, você economiza mais 25 usando o tipo Foundation, uma vez que substringToIndexassume um Intcomo parâmetro para NSStringvs um Indexstruct ( String.CharacterView.Index) para SwiftString tipos .

Devo observar que a disponibilidade dos tipos de fundação pode diferir em várias plataformas (OS X, Linux, etc). A maioria das aulas da Fundação está NSUnimplementedna versão de código aberto do Swift.

JAL
fonte
2

.mapa()

Combinar .map()com a sintaxe de fechamento à direita pode aumentar os loops. Podemos colocar as coisas que queremos iterar em uma matriz e usá .map()-las para executar alguma ação em cada elemento.

Por exemplo, podemos .map()escrever essa castanha velha, Fizzbuzz, em uma linha.

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

Fora do golfe, .map()pode ajudar a reduzir a repetição. Por exemplo, suponha que você tenha uma visão que precisa posicionar programaticamente. Você pode colocar as âncoras da exibição em uma matriz anônima e executá .map()-la para definir cada restrição .isActivecomo verdadeira, da seguinte maneira:

_ = [
        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
fonte
11
Não é melhor usar forEachno seu segundo exemplo? maprealmente deve ser usado para transformar o conteúdo de uma matriz, e não como um atalho de iteração. Nesse caso, você está descartando o resultado.
JAL
1

Atribuições variáveis ​​de golfe em estruturas de fluxo de controle usando tuplas

Considere que você deseja usar um whileloop e deseja usar a mesma coisa na condição e no bloco a seguir. Então, uma atribuição embutida em uma tupla provavelmente ajudaria. Quanto mais longo o seu atributo, melhor! Considere isto (3 bytes mais curto):

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

por cima disto:

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 a (i=k.count,i>0).1parte, que é bastante interessante.


Inspirado por uma das respostas de Herman Lauenstein .

Mr. Xcoder
fonte
1

Repetindo Strings

Infelizmente, o Swift não suporta multiplicação de String com *, da mesma forma Python. Um bom método que você pode usar é String(repeating:count:), mas infelizmente isso não é realmente golfe. Compare estas duas abordagens:

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

e

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

O segundo é um par de bytes mais curto, mas isso não pode ser usado em um fechamento ... Melhor ainda, e também funciona em fechamentos:

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

E se eu fizer isso várias vezes? Bem, você pode usar String.init(). Agora, isso pode economizar muitos bytes. Por exemplo (68 bytes):

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

em vez de (74 bytes):

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

ou (70 bytes):

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

Mas verifique se a sua String é longa o suficiente. Se você estiver usando String(repeating:"abc",3), é muito melhor usá-lo "abcabcabc".

Mr. Xcoder
fonte
+1 porque eu não tinha ideia de que variáveis ​​poderiam ser inicializadores assim.
Daniel
1

Importar

Você pode substituir import Foundationcom import UIKitpara 5 bytes mais curto, como UIKit faz importação Foundation já.

Cœur
fonte
11
Ah, você está certo. Não vi isso na revisão
mbomb007 18/07