Wskazówki dotyczące gry w golfa w Scali


24

Jakie masz ogólne wskazówki na temat gry w golfa w Scali? Szukam pomysłów, które można by zastosować do ogólnych problemów z golfem, które są przynajmniej nieco specyficzne dla Scali (np. „Usuń komentarze” nie jest odpowiedzią). Proszę zamieścić jedną wskazówkę na odpowiedź.

(To bezwstydna kopia ... w Pythonie)

Odpowiedzi:


5

zrzeczenie się: części tych odpowiedzi są uogólnieniami innych znalezionych tutaj odpowiedzi.

Użyj lambdas bez określania ich typów argumentów

Można przesłać coś takiego: a=>a.sizezamiast (a:String)=>a.size.

Użyj symboli ascii jako identyfikatorów.

Należą do nich !%&/?+*~'-^<>|. Ponieważ nie są literami, są rozdzielane osobno, gdy są obok liter.

Przykłady:

a=>b       //ok
%=>%        //error, parsed as one token
% => %      //ok
val% =3     //ok
&contains+  //ok
if(x)&else* //ok

Użyj zestawu zamiast zawiera

if (Seq(1,2,3,'A')contains x)... //wrong
if (Set(1,2,3,'A')(x))...         //right

Jest to możliwe, ponieważ Set[A] extends (A => Boolean).

Użyj funkcji curry, gdy potrzebujesz dwóch argumentów.

(a,b)=>... //wrong
a=>b=>...  //right

_Jeśli to możliwe, użyj opcji -syntax

Zasady tego są nieco niejasne, musisz czasem trochę zagrać, aby znaleźć najkrótszą drogę.

a=>a.map(b=>b.size)) //wrong
a=>a.map(_.size)     //better
_.map(_.size)        //right

Użyj częściowej aplikacji

a=>a+1 //wrong
_+1    //better, see above
1+     //right; this treats the method + of 1 as a function

Użyj ""+zamiasttoString

a=>a.toString //wrong
a=>a+""       //right

Użyj ciągów jako sekwencji

"" jest czasem najkrótszym sposobem na stworzenie pustej sekwencji, jeśli nie obchodzi cię typ aktula

Użyj BigInt do konwersji liczb na i z ciągów

Najkrótszym sposobem konwersji liczby na ciąg znaków w bazie innej niż baza 10 jest toString(base: Int)metoda BigInt

Integer.toString(n,b) //wrong
BigInt(n)toString b   //right

Jeśli chcesz przekonwertować ciąg na liczbę, użyj BigInt.apply(s: String, base: Int)

Integer.parseInt(n,b) //wrong
BigInt(n,b)           //right

Pamiętaj, że to zwraca BigInt, który jest użyteczny jak większość razy, ale nie może być na przykład używany jako indeks sekwencji.

Użyj Seq, aby utworzyć sekwencje

a::b::Nil   //wrong
List(...)   //also wrong
Vector(...) //even more wrong
Seq(...)    //right
Array(...)  //also wrong, except if you need a mutable sequence

Użyj ciągów znaków dla sekwencji znaków:

Seq('a','z') //wrong
"az"         //right

Skorzystaj ze Stream do nieskończonych sekwencji

Niektóre wyzwania wymagają n-tego elementu nieskończonej sekwencji. Stream jest idealnym kandydatem do tego. Pamiętaj Stream[A] extends (Int => A), że strumień jest funkcją od indeksu do elementu o tym indeksie.

Stream.iterate(start)(x=>calculateNextElement(x))

Używaj operatorów symbolicznych zamiast ich nieporadnych odpowiedników

:\i :/zamiast foldRightifoldLeft

a.foldLeft(z)(f) //wrong
(z/:a)(f)        //right
a.foldRight(z)(f) //wrong
(a:\z)(f)         //right

hashCode -> ##

throw new Error() -> ???

Użyj &i |zamiast &&i||

Działają tak samo dla booleanów, ale zawsze będą oceniać oba operandy

Alias ​​długa metoda jako funkcje

def r(x:Double)=math.sqrt(x) //wrong
var r=math.sqrt _            //right; r is of type (Double=>Double)

Zna funkcje w standardowej bibliotece

Dotyczy to zwłaszcza metod gromadzenia.

Bardzo przydatne metody to:

map
flatMap
filter
:/ and :\ (folds)
scanLeft and scanRight
sliding
grouped (only for iterators)
inits
headOption
drop and take
collect
find
zip
zipWithIndex3
distinct and/or toSet
startsWith

11

Najkrótszy sposób na powtórzenie czegoś jest Seq.fill.

1 to 10 map(_=>println("hi!")) // Wrong!
for(i<-1 to 10)println("hi!") // Wrong!
Seq.fill(10)(println("hi!")) // Right!

10

podejrzany identyfikator:?

Możesz użyć ? jako identyfikator:

val l=List(1,2,3)
val? =List(1,2,3)

Tutaj nic ci nie oszczędza, ponieważ nie możesz trzymać się znaku równości:

val ?=List(1,2,3) // illegal

Ale później często zapisuje jedną postać, ponieważ nie potrzebujesz ogranicznika:

print(?size)  // l.size needs a dot
def a(? :Int*)=(?,?tail).zipped.map(_-_)

Jednak często trudno jest użyć:

       print(?size)
3
       print(?size-5)
<console>:12: error: Int does not take parameters
       print(?size-5)
              ^

9

Kolekcje

Pierwszym wyborem dla losowej kolekcji jest często Lista . W wielu przypadkach możesz go zastąpić Seq , co oszczędza jedną postać instantan. :)

Zamiast

val l=List(1,2,3)
val s=Seq(1,2,3)

i chociaż s.head i s.tail są bardziej eleganckie w zwykłym kodzie, s(0)to znowu jest o jeden znak krótszy niż s.head.

W niektórych przypadkach nawet krótszy - w zależności od potrzebnej funkcjonalności jest krotka:

val s=Seq(1,2,3)
val t=(1,2,3)

natychmiastowe zapisanie 3 znaków i uzyskanie dostępu:

s(0)
t._1

to samo dotyczy bezpośredniego dostępu do indeksu. Ale w przypadku skomplikowanych koncepcji krotki zawodzą:

scala> s.map(_*2)
res55: Seq[Int] = List(2, 4, 6)

scala> t.map(_*2)
<console>:9: error: value map is not a member of (Int, Int, Int)
       t.map(_*2)
         ^

aktualizacja

def foo(s:Seq[Int])
def foo(s:Int*)

W deklaracji parametru Int * zapisuje 4 znaki nad Seq [Int]. To nie jest równoważne, ale czasami Int * wystarczy.


8

Zwykle możesz użyć mapzamiast foreach:

List("a","b","c") foreach println

można zastąpić

List("a","b","c") map println

Jedyną różnicą jest typ zwrotu ( Unitvs List[Unit]), którego i tak nie jesteś zainteresowany podczas korzystania foreach.


7

zdefiniuj krótsze typy:

Jeśli masz wiele deklaracji typu, takich jak

def f(a:String,b:String,c:String) 

krótsze jest zdefiniowanie aliasu typu i użycie go zamiast tego:

type S=String;def f(a:S,b:S,c:S)

Długość oryginału wynosi 3 * 6 = 18 Kod zastępczy to 8 (typ S =;) + 6 + 3 * 1 (= nowa długość) = 17

jeśli (n * długość <8 + długość + n), to jest to zaleta.

W przypadku klas, które są tworzone przez instancję, możemy ustawić krótszą nazwę zmiennej, aby wskazywała na ten obiekt. Zamiast:

val a=Array(Array(1,2),Array(3,4))

możemy pisać

val A=Array;val a=A(A(1,2),A(3,4))

Dotyczy to #definena przykład również C ++ , ale przyznaję, że to miłe defi valsą krótsze.
Mateusz

Hm defjest słowem kluczowym definiującym metodę, a proste tłumaczenie na c ++ for valto „const” i jest to deklaracja, ale typ jest często wywnioskowany. Skrócenie jest w pierwszym przypadku tym, type=które jest bliższe typedef- prawda? Drugi przykład nie pochodzi ode mnie i jest dla mnie nowy. Muszę uważać, gdzie go użyć.
użytkownik nieznany

typedef long long ll;jest taki sam jak #define ll long long, więc ten drugi jest krótszy o 1. Ale tak, typedefdziała. Patrząc valponownie na ten przykład, zdecydowanie go źle odczytałem. Wydaje się jeszcze mniej specyficzne dla Scali. x = thingWithAReallyLongComplicatedNameForNoReasonjest dość ogólną strategią: P
Mateusz Przeczytaj

@ userunknown Kiedy tworzysz instancję Listlub Arrayetc ze składnią val x = List(1,2,3), po prostu wywołujesz applymetodę na Listobiekcie. (Ta technika tworzenia obiektów jest znana jako „metoda fabryczna”, w przeciwieństwie do używania konstruktora z new.) Tak więc, właśnie tworzymy nową zmienną, która wskazuje na ten sam obiekt singletonu co nazwa zmiennej Array. Ponieważ jest to to samo, wszystkie metody, w tym apply, są dostępne.
Luigi Plinge, 12.11.11

7

Użyj składni infix, aby usunąć potrzebę .znaków. Nie potrzebujesz spacji, chyba że sąsiadujące elementy są zarówno alfanumeryczne, jak i oba są znakami operatora (patrz tutaj ) i nie są rozdzielone znakami zastrzeżonymi (nawiasy, przecinki itp.).

Na przykład

List(1,2,3,4).filter(_ % 2 == 0) // change to:
List(1,2,3,4)filter(_%2==0)

7

Te truei falseliterały są krótsze pisać jak 2>1na prawdziwe i 1>2fałszywych


7

Wywołaj dwukrotnie tę samą funkcję w celu inicjalizacji:

val n,k=readInt

(Widziany gdzie indziej, ale nie można go teraz znaleźć).


6

Zmień nazwy metod, jeśli ich nazwa jest długa i jeśli są używane wielokrotnie - przykład ze świata rzeczywistego:

 x.replaceAll(y,z)

 type S=String; def r(x:S,y:S,z:S)=x.replaceAll(y,z)

W zależności od możliwości zapisania „S = String” również w różnych miejscach, będzie to opłacalne tylko wtedy, gdy zastąpisz co najmniej 3 razy wszystkie.


3

Zainicjuj kilka zmiennych jednocześnie za pomocą krotki:

var(a,b,c)=("One","Two","Three") //32 characters

vs.

var a="One";var b="Two";var c="Three" //37 characters

0

Możesz także użyć zamiast =>definicji funkcji.


1
Witam i witam w PPCG. Ponieważ przez większość czasu odpowiedzi liczone są w bajtach, a nie w znakach, twoja wskazówka ma ograniczony zakres. Chciałbym rozwiązać ten problem, a także dodać tytuł wskazówki, taki jak definicje funkcji skracania w wyzwaniach golfowych opartych na liczbie znaków .
Jonathan Frech,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.