ルアでのゴルフのヒント


21

ルアでゴルフをするための一般的なヒントは何ですか?私は、少なくともLuaに特有のゴルフ問題全般のコーディングに適用できるアイデアを探しています(たとえば、「コメントを削除する」は答えではありません)。回答ごとに1つのヒントを投稿してください。


6
ヒントの質問はコミュニティwikiにしてください。しかし、「主に意見に基づく」としてこれを提出した人にとっては、言語に関するゴルフの質問のヒントは、その規則の認められた例外です。これらの質問の自由な性質は、なぜ彼らがコミュニティwikiであるかです。
ジョナサンヴァンマトレ14年

回答:


9

既に投稿されたものに加えて、ここに私が時間の経過とともに集めたいくつかのトリックを、順不同で...

  • シンボルで区切られた1つのパラメーターのみを持つ関数呼び出し("ストリング{用、テーブル用)の場合、パラメーターを括弧で囲む必要はありません。
    たとえばprint("hello")、実行する代わりに、単純に実行できます:print"hello"

  • できるだけ多くの空白を削除します-これは、文字列を閉じるシンボルの後(または最初に開く前)、関数呼び出し、テーブル...の
    代わりに特に簡単に実行print(42) a=1できますprint(42)a=1。その他の例:print(a and-1 or-2)

  • 可能な場合は、三項演算子を使用してください!代わりにif a>0 then print("hello") else print("goodbye") end、好みprint(a>0 and "hello" or "goodbye")ます。詳細はこちら
    (これは実際にはさらに良く取得することができます。print(a>0 and"hello"or"goodbye")

  • 次のことが可能な場合は、コロン呼び出し構文の砂糖を使用しstring.rep(str,12)ますstr:rep(12)。これは、このように(そしてこの方法でのみ)非変数でも機能します。("a"):rep(5)

  • 代わりに行うのでtonumber(str)だけ行いますstr+0

  • パラメーターを持たない関数の場合、通常の方法(function tick() blabla() end)で定義する代わりに、:を実行できます。ticks=loadstring"blabla()"これにより、コンテンツに応じて1バイト以上が節約されます。また、複数の関数を定義する場合は、loadstring前に1文字の変数にローカライズすると、多くのバイトを節約できます;)。このトリックはJim Bauwensの功績によるものです。

  • Luaは、空の文字列(および0他の言語とは異なります)を条件付きテストでと見なします。したがって、たとえば、実行する代わりにwhile 1 do ... end、1バイトを保存while''do ... end


(ロードストリングトリックを追加)
Adriweb 14

2
0が真の値であることはばかげている
SuperJedi224

別のstr+0同等物は~~str、優先順位のために役立つ可能性があります
フェリペナルディバティスタ

@FelipeNardiBatistaしかし、それはLua 5.3以降でのみサポートされています
Adriweb

5

すでに考えました。他の言語で動作するかどうかはわかりませんが、変数に関数を格納できるのはLuaだけです。たとえばstring.sub、プログラムでegを複数回使用する場合は、eg を使用しますs=string.sub


4
また、PythonやRubyなどの他の多くの言語でも機能します。
nyuszika7h 14

4
JavascriptとHaskellも関数値を持つことができます。
誇りに思ってhaskeller 14

これは同等ですs=("").subs=a.sub任意の変数のためのa文字列値を含みます。
エゴールスクリプチュノフ

これはファーストクラス機能と呼ばれます
Redwolfプログラム

5

ゴルフではかなり冗長な言語ですが、頭に浮かぶ一般的なヒントは次のとおりです。

  • if... then... else... endは大きな無駄であるため、条件を避けるようにしてください。
  • 代わりに、たとえば、などの短い言語構成に焦点を合わせてくださいfor i=1,5 do
  • #オペレータはかなりゴルフのための偉大な(と一般的に)です。

5

無限ループを短くする

無限ループを使用する必要がある場合、を使用することを考えますがwhile、代わりにラベルを使用すると2バイト短くなります。

while''do end
::a::goto a

できるだけ少ないスペースを使用してください

コードからさらに多くのスペースを削除するために(ab)使用できる簡単なことがあります。Luaの仕様は、変数に付ける名前について明確です。文字で始まる必要があります。数字と関数/変数の間のスペースをスキップできる場合があることを意味します

x=0>1 and 0or 1print(x)

スペースを削除する可能性は、数字に続く文字によって異なります。これを行うことができない文字は次のとおりです。

a,b,c,d,e,f            -- They would be interpreted as hexadecimal
x                      -- only fail when after a 0, other number are fine
                       -- (0x indicates the following is an hexadecimal number)

これを使用し、変数の呼び出し方に注意を払うことにより、ソースコードのほとんどをスペースフリーにすることができます。

すでにここで例を取り上げ、このアドバイスを使用して、もう1つバイトを削除できます:)。

print(a and-1 or-2)
print(a and-1or-2)

適切な入力方法を使用する

入力の主要なタイプごとにボイラープレートとコストを見ると、次のようになります。

function f(x)x end
io.read()
arg[1]

このメソッドのそれぞれは、1つの入力を取得できます。関数は、最もコストが高いものです(ただし、入力としてテーブルを取得できます)。

ゴルフをしたい場合は、コマンドライン引数を使用する方法があることがわかりますが、注意してください:さらに短くすることができます

arg[1]
...

...は、luaで少し特別です。これは、のアンパックされたコンテンツを含む変数arg、または可変機能関数の場合はアンパックされたパラメーターです。

複数の入力を取得し、それぞれを使用する必要がある場合は、変数に保存することをお勧めします。変数に2つの入力を保存する方法を次に示します

a=arg[1]b=arg[2]    -- highly un-efficient, costs 8 bytes by variable
a,b=unpack(arg)     -- costs 15, but at least doesn't depends on the number of argument
a,b=...             -- only costs 7

ここに、変数なしで実行できる最短の呼び出しを示します。

...     -- using a allow a gain of 1-2 bytes at each use
arg[2]  -- using b allow a gain of 4-5 bytes at each use

3つの引数があるポイントから、または2つの引数を使用し、1つの引数を2回使用する場合、a,b=...!:)

ifを使用することはほとんどありません!

if / elseif / ifステートメントの使用が3項よりも少ない場合はほとんどありません。そのような声明の定型文は本当に重いです:

-- exemple with dumb values
if 1>0then v=1 else v=0 end
v=1>0 and 1or 0

簡単な例では、すでに12バイトを保存していますが、elseifを実行する必要がある場合は、より重要になりますので、注意してください!

また、luaの3項は特別なものであり、それらがどのように機能するかについていくつかの条件があります。興味がある人のために、以下で説明します。

luaの三項は <condition> and <case true: have to be a true value> or <case false: can be anything>

まず、の真理値表を見てみましょうor。A orは関数と見なすことができます。常に値を返します。戻り値は次のとおりです。

x | y ||x or y
------||-------
0 | 0 ||   y
0 | 1 ||   y
1 | 0 ||   x
1 | 1 ||   x

それは私たちが三元を構築することを可能にするものです。

andそれは常に戻ります、私たちは条件を評価することを可能にするものであるy場合にはx and y評価さtrueに。

それに伴う問題は、条件がであるときに、nilまたはfalseに戻りたい場合に失敗することですfalse。たとえば、次の例は、条件がtrueであるにもかかわらず、常に5を返します。

v = true and false or 5

これがどのように機能するかを説明するための三値の段階的な評価です(それらをネストする必要がある場合に役立ちます:))

-- let's use our dumb ternary
= true and false or 5
-- and statement will be evaluated first, leading to
= false or 5
-- and we saw how the or works
= 5

回答ごとに1つのヒントをお願いします。
アタコ

「できるだけ少ないスペースを使用する」トリックは、Lua 5.2以降でのみ機能することに注意してください。
Adriweb

4

私もいくつかのヒントをまとめました。私の一部はすでに述べたものと重複すると確信していますが、より完全な回答を作成するためにそれらを何らかの形で含めます。


繰り返し機能を変数に割り当てる

Luaでは、関数を変数に割り当てることができます。1文字の変数でも。つまり、関数をstring.sub(x, y)2回以上繰り返すと、変数に割り当てることでメリットが得られます。

変数に割り当てない場合(69文字):

print(string.sub(x, y))
print(string.sub(x, y))
print(string.sub(x, y))

変数への割り当て(51文字):

s=string.sub
print(s(x,y))
print(s(x,y))
print(s(x,y))

これをさらに一歩進めることができる場合があります。Luaでは、次のようにOOPが文字列を操作できます。str:sub(x, y)またはstr.sub(x, y)これにより、コードの新しいオプションが開きます。図に示すように、参照によって変数を関数に割り当てることができます(46文字)。

s=z.sub
print(s(x, y))
print(s(x, y))
print(s(x, y))

最も効率的な方法で文字列を解析します

Luaでforループを使用し、string.sub文字ごとに反復することに気付くかもしれません。必要に応じて、これが最適に機能する場合もありますが、string.gmatchがより少ない文字で機能する場合もあります。以下に両方の例を示します。

s=io.read()
for a = 1, s:len() do
    print(s:sub(a, a))
end 

for i in io.read():gmatch('.') do
    print(i)
end

そして、ゴルフをするとき、違いはより顕著です:

s=io.read()for a=1,s:len()do print(s:sub(a, a))end

for i in io.read():gmatch'.'do print(i)end

ホワイトスペースを最適化するための割り当ての再構築

Luaでは、閉じ括弧または終了引用符と次の文字の間にスペース文字を入れる必要はありません。これまでのところ、私はこれを念頭に置いて再構築するとキャラクターがカットされる2つのケースを見つけました。

  • 変数の割り当て:

     x,y=io.read(),0 print(x)
     vs.
     y,x=0,io.read()print(x)
    
  • Ifステートメント:

     if x:sub(1,1)==1 then
     vs
     if 1==x:sub(1,1)then
    

できるだけ少ない文字を返します

trueまたはfalseの値を返す必要がある場合、戻り値には少なくとも5文字を使用する必要があるようです。実際には、以下も同様に機能します。

return true
return false
vs
return 1>0
return 0>1

素晴らしいヒント、私はあなたの投稿の編集を提案する自由を取りました。のみnilfalse交換についてあなたのヒントので、LUAでfalseと評価され、他のすべては、真であるx==0x==""x==''によってはxfalseです。現在nil:)に変更しています。
かてんきょう16

ああ、あなたは正しいです。それを修正してくれてありがとう!
Skyl3r 16

2

これらはLuaのみ(と思う)の最適化です。

文字列は、算術演算を行うときに自動的に数値に変換されます。条件文に注意してください、それらは自動的に変換しません。これは、スペースを節約しながらユーザー入力を数値として取り込むのに最適です。

2つの変数の内容を切り替えるには、一時変数は必要ありません。a,b=b,aaとbの値を交換します。

また、上記で述べたことを拡張するために、任意の英数字が非英数字に触れることができます。そうa,b=io.read():match"(.+)/(.+)"u,v=a,bであっても空白の欠如と、スクリプト作業、完璧です。


2

ローカル変数の割り当てを組み合わせる

の代わりに:

local a=42
local b=17
local c=99

並列割り当てを使用します。

local a,b,c=42,17,19

変数ごとに6バイトが節約されました!

未使用の関数パラメーターを使用してローカル変数を宣言する

の代わりに:

function foo(a,b) local c,d ... end
function bar(a,b) local c,d=42,17 ... end

つかいます

function foo(a,b,c,d) ... end
function bar(a,b,c,d) c,d=42,17 ... end

6バイト節約(重複する可能性のある変数ごとにマイナス1-2バイト)。


1
localあなたが別の名前を使用する必要があるため、ゴルフをするときに使用が正当化される場合は絶対にないため、ダウン投票されました。地元の人々を
活用

1

可変長関数

あなたを悩ます主な可変機能はprint()です。たとえば、一緒String.gsub()に使用している場合、変更した文字列とgsubトリガーされた回数が出力されます。

その2番目の出力を抑制するにはgsub、括弧でカプセル化して1つの値のみを返すようにします

print(String.gsub("aa",".","!"))    -- outputs "!!    2\n"
print((String.gsub("aa",".","!")))  -- outputs "!!\n"

1

出力方法を知っている

luaで出力する主な方法は2つあります

io.write()    -- outputs without trailing newline
print()       -- outputs with trailing new line and shorter by 3 bytes

複数回連結する必要がある場合io.write()は、標準の連結演算子の代わりに1文字の変数に割り当てられたものを使用することで短縮できます。..

i(a)    -- i was defined as io.write
s=s..a

前払いで通話ごとに2バイト獲得

i=io.write  -- longer by 6 bytes
s=""

3番目の連結でさえ、4番目にバイトを獲得し始めます。


3
それはprintありませんprintf
valは、

@valうわー、私はどうすればその間違いをすることができるかさえ知りません。それを指摘してくれてありがとう、編集します
Katenkyo

1

順不同の一連のヒント:

  • stringかなり長い名前です。効率的に、('').charと同じstring.charです。変数のセミコロンと組み合わせて使用​​すると、さらに良い結果が得られます:a=...; print(a:sub(1, 5))、一部のstring関数は入力として文字列を受け取りません。
  • Luaはほとんどの場合、文字列と数値の間に自動変換を持っているので、tonumberそして+0多くの場合のみバイトを無駄に。
  • 常にのload'your function code here'代わりに使用しますfunction()your function code here end...inside を使用して関数の引数にアクセスします。
  • Luaの一部の文字列関数は、意図しない方法で使用される可能性があります!たとえばa:gsub('.',load'my function')、文字列内の文字を反復処理する最短の方法のようです
  • 文字列エンジンは強力ですが、ユーザー入力をパターンとして使用する場合はその力に注意してください!そのため、使用する必要がある場合がありますa:find('.',1,1)(この問題をテストするに%は、入力のさまざまな場所に含めて、結果をチェックアウトします)。Luaが入力をパターンとして解析しようとしたため、無数のアイデアが壊れました。
  • nil3バイト、_1 バイトです(ランダムな名前であり、ほとんど存在しません)。また、どの数字も真理値として機能します。
  • 背後にあるロジックを知ってくださいx and i or o。これは単なる三項演算子ではなく、完全な論理式です。実際、次のことを意味します:「x真であるi場合、試してください。xまたはiのいずれかが偽である場合、oを返します」。したがって、iが真実でない場合、結果はoです。また、両方andまたはor一部を省略できます(x and ix or o)。
  • 以下の代わりに1による整数除算を使用してくださいmath.floor5.3//1==5.0。結果の数値は常に入力タイプ(整数/浮動小数点数)の後に続くことに注意してください。

1
「また、どの数字も真理値として機能します。」これには0が含まれることを詳しく説明したかったのですが、これはC / C ++のバックグラウンドの一部のコーダーにとってあまり直感的ではないかもしれません。
ouflak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.