Советы по игре в гольф в Скале


24

Какие общие советы у вас есть для игры в гольф в Скала? Я ищу идеи, которые могут быть применены к задачам по коду для игры в гольф, которые, по крайней мере, несколько специфичны для Scala (например, «удалить комментарии» - это не ответ). Пожалуйста, оставьте один совет за ответ.

(Это бесстыдная копия ... в Python)

Ответы:


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

Используйте Set вместо содержит

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

Используйте строки как последовательности

"" иногда самый короткий способ создать пустую последовательность, если вам не важен тип actula

Используйте BigInt для преобразования чисел в и из строк

Самый короткий способ преобразовать число в строку в базе, отличной от базы 10, - это toString(base: Int)метод BigInt.

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

Используйте Stream для бесконечных последовательностей

Некоторые проблемы требуют n-го элемента бесконечной последовательности. Stream является идеальным кандидатом для этого. Помните 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

Коллекции

Первым выбором для случайной коллекции часто является список . Во многих случаях вы можете заменить его на Seq , который сохраняет один символ Instantan. :)

Вместо того

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 * сохраняет 4 символа вместо Seq [Int]. Это не эквивалентно, но иногда 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короче.
Мэтью Прочитал

Гектометр defэто ключевое слово для определения метода, и простой перевод в c ++ для valэто «const», и это объявление, но тип часто выводится. Укорочение в первом случае type=ближе к typedef- не так ли? Второй пример не от меня, и он новый для меня. Я должен остерегаться, где его использовать.
пользователь неизвестен

typedef long long ll;так же, как #define ll long longи последний короче на 1. Но да, typedefработает. Посмотрев на valпример еще раз, я определенно неправильно понял. Кажется, еще менее специфичным для Scala. x = thingWithAReallyLongComplicatedNameForNoReasonдовольно общая стратегия: P
Мэтью Рид

@userunknown Когда вы создаете экземпляр Listили и Arrayт. д. с синтаксисом, val x = List(1,2,3)вы просто вызываете applyметод Listобъекта. (Этот метод для создания объекта известен как «фабричный метод», в отличие от использования конструктора с new.) Итак, выше, мы просто создаем новую переменную, которая указывает на тот же единственный объект, что и имя переменной Array. Поскольку это одно и то же, все методы, в том числе apply, доступны.
Луиджи Плинге

7

Используйте синтаксис инфикса, чтобы убрать необходимость в .символах. Вам не нужны пробелы, если соседние элементы не представлены как в буквенно-цифровом, так и в символах оператора (см. Здесь ) и не разделены зарезервированными символами (скобками, запятыми и т. Д.).

Например

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

7

Эти trueи falseлитералов короче , чтобы писать , как 2>1для истинного и 1>2за ложные



6

Переименуйте методы, если их имя длинное, и если они используются несколько раз - пример из реальной жизни:

 x.replaceAll(y,z)

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

В зависимости от возможности сохранения 'S = String' также в разных местах, это будет экономически выгодно, если заменить хотя бы все 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. Поскольку большую часть времени ответы считаются в байтах, а не в символах, ваш совет имеет ограниченную сферу применения. Я хотел бы обратиться к этому, а также добавить заголовок подсказки, такой как определение функции Сокращения в задачах по коду, основанных на подсчете символов .
Джонатан Фрех
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.