Swift'de golf için ipuçları


24

Swift'de kod golf oynamak için bazı ipuçları nelerdir? Güvenliğe odaklanması golf oynamayı zorlaştırıyor gibi görünüyor, ancak bu küçük ipuçlarını ve daha da faydalı olmasını sağlıyor. Swift'de bazı uygulamalarda kod golfünde başarılı olmasına yardımcı olabilecek herhangi bir özellik var mı?

Lütfen cevap başına bir ipucu gönderin.


11
Bize güvenebilirsin - eğer güvenli olması gerekiyorsa, golf oynayacak!
Conor O'Brien,

9
Umarım bazı iyi ipuçları çabuk gelir.
DJMcMayhem

4
Hızlı golf? Golfün yavaş tempolu, sakin bir oyun olduğunu
sanıyordum

Yanıtlar:


6

aralıklar

Gerçekten yararlı olan bir şey, ...ya da ..<işleçlerini kullanarak aralıklar oluşturmak

Örneğin

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

Böylece, bir dizinin 2. ve 4. değerlerini elde etmek için

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

Pratik kullanım

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

kullanma

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

8 bayttan daha kısa

for n in 0...3{let v=a[n];print(v)}

4
for n in 0...3{print(a[n])}Geçerli değil mi?
Julian Wolf

4

Kapaklar:

Değişkenlerin kullanımı, bir işlevi tutma yerine, bir işlevi kullanma yardımcı olabilir:

65 bayt:

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

66 bayt:

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

Buradaki küçük fark, ancak bazı bulmacalarda daha fazla gösterilecektir.

Kısaltma İşlevleri:

Önceki örneğe bakmak bana bir şey hatırlatıyor. Bazen, bir işlevi yeterince kullanacaksanız, yeniden adlandırmak için boşluğa değer olabilir:

Bu:

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

Buna:

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

Veya, aslında, bu daha iyidir:

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

Bu şekilde r("Hello World",8)yerine sadece araString(repeating:"Hello World",count:8)

Dışarı Çıkma Tip Beyanları:

Bir zamanlar argüman tipini ayarlamadan bir kapanış oluşturdum, böylece daha kısa bir cevap oluşturdum:

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

Derleyici olduğu sonucu çıkarılan iiçindedir Int.

Hızlı Yol Dizileri Yaratın:

Bir diziye ihtiyacınız varsa Ints, Rangeoluşturmak için a kullanın:

Array(0...5)

Bu aynı şeyi yapar:

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

Dizileri Ifveya YerineSwitch :

Bunu yapmak yerine:

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

Muhtemelen bunu yapabilirsin:

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

Kısaltılmış Türleri:

Tür dönüştürmeyi çok kullanıyorsanız, bir tür diğer adı oluşturmak isteyebilirsiniz:

typealias f=Float

Harita:

returnAnahtar kelimeyi anahtar kelimede sık kullanmanız gerekmediğini unutmayın .map .

Swift Online Koşu:

Her ne kadar Çevrimiçi Deneyin , Swift'i şimdi desteklemiyor olsa da !


2
Gönderi için teşekkürler. Bana çok yardım etti. tio.run/nexus şimdi hızlı bir şekilde çalışıyor :)
palme

3

try

Swift 2.x ve üzeri sürümlerde, bir işaretçiyi bir NSErrornesneye işlev parametresi olarak geçirerek hataları geleneksel olarak işleyen işlevlerthrow .

Bunun anlamı:

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

şimdi şuna benziyor:

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

Bu kullanılarak kısaltılabilir try?ya da try!. hata atılırsa try?ifadesini değerlendirir nil. try!bir hata atıldığında programınıza çökecek ve yalnızca hiçbir zaman hata atılmayacak durumlarda kullanılmalıdır.

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

try?ve döngüden try!en az 13 bayt kaydedin do-try-catch. Ayrıca []seçenekler yerine boş bir diziye ( ) geçerek de en az bir bayt daha tasarruf ettiğinizi unutmayın nil.


3

Dizileri Azaltma

for-in loopsİçindeki öğelerin toplamı veya öğelerinin ürünü gibi tek bir değer elde etmek için bir dizi ile yineleme yapmak , gerçekte ne kadar basit olduğu için çok uzun olabilir. Sadece reduce()yöntemi kullanabilirsiniz . Bazı örnekler:

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

Bir dizideki öğeleri for-indöngülerle ekleme :

var sum = 0

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

basitleştirilebilir:

print(array.reduce(0, +))

Ve for-in döngülerle dizinin içindeki elemanların ürününü elde etmek:

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

ayrıca şu şekilde azaltılabilir:

print(array.reduce(1, *))

**İşlevi bildirerek, yalnızca powelle çağıracağınızdan daha fazla bayt kaybetmez misiniz ?
JAL

@ JAL evet, ancak 10 kez pow çağırırsanız, az miktarda bayt tasarrufu sağlar. Gerçekten en iyi golf tekniği değil, ancak başka bir potansiyel yardım. Özellikle pow için düşünülmedi, ancak asal sayıları aramak gibi diğer işlemler için, eğer bunu 3 kez yaparsanız, büyük miktarda bayt kazandırır
Bay Xcoder

2

Swift'in üçlü operatörü çok özlü: condition ? action : othereylem

Durum doğruysa, bir şey yapın, değilse başka bir şey yapın.

textColor = bgIsBlack ? .white : .black

Bu textColor, arka plan siyahsa beyaz, arka plan başka bir renkse siyah olur.

Nil birleştirme operatörü daha da kötüsüdür: a ?? b

Diyelim ki JSON'u belirli bir anahtar için kontrol ediyorsunuzdur, böylece anahtarın değerini başlık metni olarak sunabilirsiniz. Anahtar mevcut değilse (yani değer sıfır), başlık varsayılan metnini vermek istiyoruz.

title = keysValue ?? "Not Available"

2

sayım

Sen zinciri olabilir forEachgelen enumerated()bir koleksiyon türüne koleksiyonu, yanı sıra endeksinde nesne (veya değer türü) bir başvuru almak için:

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

veya

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

veya (daha kısa CountableClosedRangesözdizimi)

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

Baskılar:

0 1
1 2
2 3
3 4
4 5

2

substring

Bazen, saf Swift türlerini kullanmak yerine Temel türlerine geri dönerek byte tasarruf edebilirsiniz. NSStringSwift Stringtürü vs bir alt dizgine erişerek karşılaştırın :

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

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

xAn olarak bildirilerek kaybedilen 9 karakter olsa bile NSString, Foundation türünü kullanarak 25 daha fazla tasarruf edersiniz, çünkü Swift türleri için bir yapıya ( vs) parametre olarak substringToIndexalır .IntNSStringIndexString.CharacterView.IndexString

Foundation türlerinin kullanılabilirliğinin birden fazla platformda (OS X, Linux vb.) Farklılık gösterebileceğini unutmayın. Çoğu Hazırlık sınıfı NSUnimplementedSwift'in açık kaynaklı versiyonundadır.


2

) (.MAP

.map()Firar kapatma sözdizimi ile birleştirmek , döngüler için sıkılaştırır. Tekrarlamak istediklerimizi bir diziye koyabiliriz, sonra .map()her eleman üzerinde bir eylem yapmak için kullanabiliriz .

Örneğin, .map()eski kestane Fizzbuzz'ı bir satırda yazmak için kullanabiliriz .

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

Golf dışında .map(), tekrarlamanın azaltılmasına yardımcı olabilir. Örneğin, programatik olarak konumlandırmanız gereken bir görüntünüz olduğunu varsayalım. Görünümün bağlantılarını anonim bir diziye .map()yerleştirip her kısıtlamayı .isActivedoğru yapmak için üzerine koyabilirsiniz :

_ = [
        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 }

1
forEachİkinci örnekte kullanmak daha iyi değil mi? mapgerçekten bir dizinin içeriğini dönüştürmek için kullanılmalı ve yineleme kısayolu olarak kullanılmamalıdır. Bu durumda, sonucu atarsınız.
JAL

1

Tuples kullanarak kontrol akışı yapılarında golf değişken atamaları

Bir whiledöngü kullanmak istediğinizi ve aynı şeyi hem durumda hem de takip edilecek blokta kullanmak istediğinizi düşünün . Daha sonra, bir satır içindeki satır içi atama büyük olasılıkla yardımcı olacaktır. Özellik ne kadar uzunsa, o kadar iyi! Bunu düşünün (3 bayt daha kısa):

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

bunun üstünde:

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

(i=k.count,i>0).1Oldukça ilginç olan kısmı dikkat edin .


Herman Lauenstein'ın cevaplarından biri esinlenerek .


1

Tekrarlanan Dizeler

Ne yazık ki, Swift *aynı şekilde Python ile String çarpımını desteklemiyor . Bunun yerine kullanabileceğiniz iyi bir yöntem String(repeating:count:), ancak ne yazık ki bu gerçekten golf değil. Bu iki yaklaşımı karşılaştırın:

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

ve

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

İkincisi, bir kaç bayt daha kısadır, ancak bu bir kapatma işleminde kullanılamaz ... Daha da iyisi ve aynı zamanda kapaklarda da çalışır:

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

Peki ya bunu birden çok kez yaparsam? Peki, kullanabilirsiniz String.init(). Şimdi, bu çok fazla bayt tasarrufu sağlayabilir. Örneğin (68 bayt):

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

yerine (74 bayt):

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

veya (70 bayt):

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

Ancak String'inizin yeterince uzun olduğundan emin olun. Kullanıyorsanız String(repeating:"abc",3), bunun yerine kullanmak daha iyidir "abcabcabc".


+1 çünkü hiçbir fikrim değişkeni böyle bir başlatıcı olabilirdi.
Daniel

1

İthalat

UIKit zaten Foundation'ı içeri aktardığı için, 5 byte daha kısa bir süre import Foundationile değiştirebilirsiniz import UIKit.


1
Ah haklısın. Bu incelemede
görmedim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.