斯卡拉高尔夫技巧


24

您在斯卡拉打高尔夫球有哪些一般秘诀?我正在寻找可用于编码至少在某种程度上特定于Scala的高尔夫问题的想法(例如,“删除评论”不是答案)。请为每个答案发布一个提示。

(这是Python中...的无耻复制)

Answers:


5

免责声明:部分答案是此处找到的其他答案的概括。

使用lambda而不指定其参数类型

可以提交这样的内容: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)

需要两个参数时,请使用curried函数。

(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

使用字符串作为序列

"" 如果您不在乎actula类型,有时是创建空序列的最短方法

使用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,大多数情况下,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

利用Stream无限序列

一些挑战要求无限序列的第n个元素。Stream是此的理想人选。请记住Stream[A] extends (Int => A),即流是从索引到该索引处的元素的函数。

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

使用符号运算符而不是冗长的对应符号

:\:/不是foldRightfoldLeft

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


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 * length <8 + length + n),那么这是一个优势。

对于通过工厂实例化的类,我们可以设置较短的变量名称以指向该对象。代替:

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

我们可以写

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

#define例如,这也适用于C ++ ,但我承认这样做很好,def而且val更短。
马修·

def是定义方法的关键字,对c ++的简单翻译val是'const',它是一个声明,但是通常会推断出类型。在第一种情况下,起酥油type=更接近typedef-是吗?第二个例子不是我的,对我来说是新的。我必须提防,在哪里使用它。
用户未知

typedef long long ll;与相同#define ll long long,因此后者要短1。但是,typedef确实可以。val再次看这个例子,我肯定会误读它。似乎与Scala无关。 x = thingWithAReallyLongComplicatedNameForNoReason是一个相当普遍的策略:P
马修(Matthew)

@userunknown当使用语法实例化Listor Array等时,val x = List(1,2,3)您只是applyList对象上调用方法。(与使用new。构造函数相反,这种创建对象的技术被称为“工厂方法” 。)因此,在上面,我们只是制作了一个新变量,该变量指向与变量名相同的单例对象Array。由于是同一件事,因此所有方法(包括apply)都可用。
路易吉·普林格

7

使用infix语法消除对.字符的需要。除非相邻的项目都是字母数字或运算符(请参见此处),并且不由保留字符(括号,逗号等)分隔,否则不需要空格。

例如

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

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

0

您也可以使用代替=>函数定义。


1
您好,欢迎来到PPCG。由于大多数时候,答案都是按字节而不是字符计数的,因此提示的范围有限。我将解决此问题,并在基于字符数的代码高尔夫挑战赛中添加一个提示标题,例如“ 缩短函数定义”
乔纳森·弗雷希
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.