스칼라 골프 팁


답변:


5

면책 조항 :이 답변의 일부는 여기에있는 다른 답변의 일반화입니다.

인수 유형을 지정하지 않고 람다 사용

a=>a.size대신 다음과 같은 것을 제출할 수 (a:String)=>a.size있습니다.

ASCII 기호를 식별자로 사용하십시오.

이 포함됩니다 !%&/?+*~'-^<>|. 문자가 아니기 때문에 문자 옆에 있으면 구문 분석됩니다.

예 :

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

포함 대신 세트 사용

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

이 때문에 가능합니다 Set[A] extends (A => Boolean).

두 개의 인수가 필요할 때 커리 함수를 사용하십시오.

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

_가능 하면 -syntax를 사용하십시오.

이것에 대한 규칙은 다소 모호하므로 때로는 가장 짧은 길을 찾기 위해 조금 놀아야합니다.

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

부분 적용 사용

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

""+대신에 사용toString

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

문자열을 시퀀스로 사용

"" 때로는 액 츄라 타입에 신경 쓰지 않으면 빈 시퀀스를 만드는 가장 짧은 방법입니다

BigInt를 사용하여 숫자를 문자열로 변환

밑이 10이 아닌 밑의 문자열로 숫자를 변환하는 가장 짧은 방법은 BigInt의 toString(base: Int)방법을 사용하는 것입니다

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

문자열을 숫자로 변환하려면 BigInt.apply(s: String, base: Int)

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

이렇게하면 대부분의 경우처럼 사용할 수 있지만 시퀀스의 인덱스로 사용할 수없는 BigInt가 반환됩니다.

Seq을 사용하여 시퀀스 생성

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

문자 순서에 문자열을 사용하십시오.

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

무한 시퀀스에 스트림 사용

일부 과제는 무한 시퀀스의 n 번째 요소를 요구합니다. 스트림은 이에 대한 완벽한 후보입니다. 즉 Stream[A] extends (Int => A), 스트림은 인덱스에서 해당 인덱스의 요소까지의 함수입니다.

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

까다로운 상대 대신 기호 연산자를 사용하십시오.

:\그리고 :/대신 foldRight하고foldLeft

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

hashCode -> ##

throw new Error() -> ???

사용 &하고 |대신 &&하고||

부울에 대해서도 동일하게 작동하지만 항상 두 피연산자를 모두 평가합니다.

함수로서의 별칭 긴 방법

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

표준 라이브러리의 기능 이해

이것은 특히 수집 방법에 적용됩니다.

매우 유용한 방법은 다음과 같습니다.

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

무언가를 반복하는 가장 짧은 방법은입니다 Seq.fill.

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

10

의심스러운 식별자 :?

당신이 사용할 수있는 ? 식별자로 :

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

여기에 등호를 붙일 수 없기 때문에 아무것도 저장하지 않습니다.

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

그러나 나중에 구분 기호가 필요하지 않기 때문에 종종 하나의 문자를 저장합니다.

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

그러나 종종 다음과 같이 사용하기 까다 롭습니다.

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

9

컬렉션

무작위 컬렉션의 첫 번째 선택은 종종 List 입니다. 대부분의 경우이 문자 를 Seq바꾸면 하나의 문자를 저장합니다. :)

대신에

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

s.head 및 s.tail은 일반적인 코드에서 더 우아하지만 s(0)다시 한 문자보다 짧습니다 s.head.

필요한 경우 기능에 따라 더 짧은 경우도 있습니다.

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

3 자 즉시 저장 및 액세스 :

s(0)
t._1

직접 인덱스 액세스에서도 동일합니다. 그러나 정교한 개념의 경우 튜플이 실패합니다.

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

최신 정보

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

매개 변수 선언에서 Int *는 Seq [Int]에 4자를 저장합니다. 동등하지 않지만 때로는 Int *가 수행합니다.


8

일반적으로 다음 map대신 사용할 수 있습니다 foreach.

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

로 교체 가능

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

유일한 차이점은 반환 유형 ( Unitvs List[Unit]) foreach입니다.


7

더 짧은 유형을 정의하십시오.

같은 유형의 선언이 여러 개인 경우

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

유형 별명을 정의하는 것이 더 짧으며 대신 사용하십시오.

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

원래 길이는 3 * 6 = 18입니다. 교체 코드는 8 (유형 S =;) + 6 + 3 * 1 (= 새 길이) = 17입니다.

(n * 길이 <8+ 길이 + n)이면 이점이됩니다.

팩토리를 통해 인스턴스화되는 클래스의 경우 해당 객체를 가리 키도록 더 짧은 변수 이름을 설정할 수 있습니다. 대신에:

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

우리는 쓸 수있다

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

이것은 C로 ++뿐만 아니라과 적용 #define예를 들어,하지만 난 것을 그것의 좋은 인정 def하고 val짧다.
Matthew 읽기

흠. def는 메소드를 정의하는 키워드이며, C ++ 로의 간단한 번역 val은 'const'이며 선언이지만 유형은 종종 유추됩니다. 단축은 첫 번째 경우에 type=더 가깝 typedef습니다. 두 번째 예는 나에게서 온 것이 아니며 나에게 새로운 것입니다. 어디에서 사용해야하는지 조심해야합니다.
사용자 알 수 없음

typedef long long ll;와 동일 #define ll long long하므로 후자는 1만큼 짧습니다. 그러나 그렇습니다 typedef. val예제를 다시 보면 분명히 잘못 읽었습니다. 스칼라에 덜 영향을주는 것 같습니다. x = thingWithAReallyLongComplicatedNameForNoReason꽤 일반적인 전략입니다 : P
Matthew

@userunknown 구문으로 a List또는 Arrayetc 를 인스턴스화 할 때 객체 val x = List(1,2,3)에서 apply메소드를 호출하기 만하면 List됩니다. (이 객체 생성 기법은와 함께 생성자를 사용하는 것과 달리 "공장 방법"이라고 new합니다.) 위에서 우리는 변수 이름과 동일한 싱글 톤 객체를 가리키는 새로운 변수를 만들고 Array있습니다. 같은 것이기 때문에를 포함한 모든 방법 apply을 사용할 수 있습니다.
Luigi Plinge

7

.문자 의 필요성을 제거하려면 접두어 구문을 사용하십시오 . 인접한 항목이 영숫자 또는 연산자 문자 ( 여기 참조 )로되어 있고 예약 문자 (괄호, 쉼표 등)로 구분 되지 않은 경우 공백이 필요하지 않습니다 .

예 :

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

7

truefalse리터럴은 쓰기에 짧은 2>1진실과 1>2거짓에 대한


7

초기화를 위해 동일한 함수를 두 번 호출하십시오.

val n,k=readInt

(다른 곳에서 보았지만 지금 찾을 수 없습니다).


6

이름이 길고 여러 번 사용되는 경우 메소드 이름 바꾸기-실제 예 :

 x.replaceAll(y,z)

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

다른 장소에도 'S = String'을 저장할 수있는 가능성에 따라, 적어도 replaceAll을 3 번 교체하면 경제적 일뿐입니다.


3

튜플을 사용하여 여러 변수를 한 번에 초기화하십시오.

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

vs.

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

0

함수 정의 에 사용 하는 대신 사용할 수도 있습니다 =>.


1
PPCG에 오신 것을 환영합니다. 대부분의 경우 답변은 문자가 아닌 바이트로 계산되므로 팁의 범위는 제한적입니다. 이 문제를 해결하고 문자 수 기반 코드 골프 문제에서 함수 정의 단축 과 같은 팁 제목을 추가합니다 .
Jonathan Frech
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.