OOP:指向プログラミングの重複


32

コードゴルフに適していると思われるあまり知られていないプログラミングパラダイムの1つは、オーバーラップ指向プログラミング(OOP) *です。部分的に同一のコードを記述する場合、同一の部分を単にオーバーラップし、2つの元のコード行の開始位置を何らかの方法で記憶することにより、多くのバイトを節約できます。あなたの仕事は2書くことです重複したプログラムまたは機能をcompressしてdecompress、以下の仕様で:

*本番コードではおそらく使用しないでください。

compress

compress任意の便利な形式の2つの文字列を取り、可能な限りそれらをオーバーラップします。これは、s両方の入力文字列がの部分文字列であるような最小長の文字列ですs。さらに、両方の文字列の開始インデックスと終了インデックスを識別する出力が返されます。

例:(正確なIOフォーマットはあなた次第です)

compress("abcd", "deab") -> "deabcd" ((2,5),(0,3))
compress("abcd", "bc")   -> "abcd" ((0,3),(1,2))
compress("abc", "def")   -> "abcdef" ((0,2),(3,5)) or "defabc" ((3,5),(0,2))

decompress

decompressの逆関数を計算しますcompress。これは、文字列と2つの開始インデックスと終了インデックス(によって返される形式で)が与えられcompress、2つの元の文字列を返します。有効な入力のみを処理する必要があります。以下の等式は、すべての文字列のために保持する必要がありs1s2

(s1, s2) == decompress (compress (s1, s2))

例:(例のcompress

decompress "deabcd" ((2,5),(0,3)) -> "abcd" "deab" 
decompress "abcd" ((0,3),(1,2))   -> "abcd" "bc"

decompress "abcdef" ((0,2),(3,5)) -> "abc" "def"   
 or (whichever version your "compress" generates)
decompress "defabc" ((3,5),(0,2)) -> "abc" "def"

得点

スコアは、を呼び出して返される文字列のサイズですcompress("<code of compress>", "<code of decompress>")。これはので、スコアが低いほど良いです。

例:

あなたの関数のコードと仮定しcompressているc=abcdとのコードdecompressですd=efghi。次にcompress("c=abcd", "d=efghi")"c=abcd=efghi"(およびインデックス、ただしスコア付けに影響しない)が得られるため、スコアはになりlength "c=abcd=efghi" = 12ます。

追加の規則

  • この挑戦の精神では、あなたcompressとあなたの少なくとも1つのキャラクターdecompress が重複する必要があります。コメントを追加することでこれを簡単に達成できますが、そうするとスコアが増加し、本質的に重複するコードを使用した短いソリューションが存在する可能性があることに注意してください。
  • compressそして、decompressあなたが定義するために使用したすべての文字と同様に、印刷可能なASCII文字を含む文字列を処理できる必要がcompressありdecompressます。
  • インデックスは、ゼロまたは1インデックスにすることができます。
  • あなたのプログラムや機能が実際に名前を付ける必要はありませんcompressdecompress

さまざまなコマンドライン引数を使用して、コードの圧縮と解凍を実行できますか?
MildlyMilquetoast

確かに。2つのプログラムを指定する必要があり、サイトポリシーでは、カウントされている限りコマンドライン引数を許可しているため、プログラムごとに異なるコマンドライン引数を指定できます。
ライコニ

回答:


25

GNU Prolog、105ポイント

s(U,L/M,C):-prefix(A,C),length(A,M),suffix(U,A),length(U,L).
o(A-B,C-X-Y):-length(C,_),s(A,X,C),s(B,Y,C).

(これには移植性がないためprefix、GNU Prologが必要suffixです。)

プロローグには、この課題に対する興味深い主な利点が1つあります。複数の呼び出しパターンを処理する関数を作成できます(つまり、対応する出力を取得するために関数に入力を与えることができるだけでなく、対応する入力を取得するために関数に出力を与えることができます)。そのため、圧縮と解凍の両方を処理できる関数を定義できますo。これにより、双方向で機能する関数を定義する105バイトの送信が行われます。(ちなみに、私はほとんどの場合、これをより簡単な減圧装置として作成し、「無料で」コンプレッサーを入手しました。)一般に、Prologでこのタスクを実行する非常に短いプログラムが期待できます。文字列の処理時(不足しているプリミティブの点、および問題のプリミティブがひどく長い名前を持っている点)。

への最初の引数oは、文字列のタプルです(例:)"abcd"-"deab"。2番目の引数の形式は次のとおり"deabcd"-4/6-4/4です。これはかなり標準的なネストされたタプルで、文字列が「deabcd」で、最初の文字列の長さが4で6文字目で終わり、2番目の文字列の長さが4で4文字目で終わることを意味します。(GNU Prologの文字列は単なる文字コードのリストであり、実装ではデフォルトで後者の解釈が優先されるため、デバッグが煩わしいことに注意してください。)o一方の引数は、もう一方を出力します(つまり、最初の引数を指定するとコンプレッサーとして機能し、2番目の引数を指定するとデコンプレッサーとして機能します)。両方の引数を指定すると、圧縮された表現が指定された文字列と一致することを確認します。引数をゼロにすると、次のような出力が生成されます。

| ?- o(X,Y).
X = []-[]
Y = []-0/0-0/0 ? ;

X = []-[]
Y = [_]-0/0-0/0 ? ;

X = []-[A]
Y = [A]-0/0-1/1 ? ;

many lines later

X = [A]-[B,A,C]
Y = [B,A,C]-1/2-3/3 ? ;

上記のI / O形式の説明も、ほとんど完全にプログラムの説明です。プログラムにはほとんど何もありません。唯一の微妙な点は、評価順序のヒントに関することです。プログラムは、終了が保証されている検索戦略を使用するだけでなく、できるだけ短い出力文字列を生成することを保証する必要があります。

圧縮するときは、length(C,_)(「C長さがある」)から始めます。これは、多くのPrologおよびBrachylogの回答で使用したトリックです。これがPrologが最初に目にするものである場合、C他のものよりも長さを減らすことを優先させます。これにより、最小長が確保されCます。の制約の順序sは慎重に選択されるため、検索の候補の長さごとに有限時間がかかりCます。、by 、by 、およびbyによってA制約されますC(わかりませんがC、ターゲットの値はわかっています)。したがって、検索に無制限の時間がかかることはありません。MAUALU

解凍するときC、ユーザーから直接与えられます。これにより、制約のシーケンスが同じであるため、プログラムが有限時間で実行されます。(プロローグの評価順序を認識している人々は、の定義があることに注意しますs配置し、解凍するときに、非常に非効率的であるlength(A,M)length(U,L)最初に高速になりますが、移動length(A,M)圧縮するためでもない時に開始するには、無限ループを引き起こす可能性AM一度に何に縛られます)


13

Brachylog50 46バイト

{Ċ∧Lċ₂l∧Lgj:?z{tT∧?h~cṪhlI∧ṪbhTl:I+-₁:I↔}ᵐ:L}

オンラインでお試しください!

解凍:

~{Ċ∧Lċ₂l∧Lgj:?z{tT∧?h~cṪhlI∧ṪbhTl:I+-₁:I↔}ᵐ:L}

オンラインでお試しください!

@ ais523のおかげで5バイト節約

説明

宣言型言語の良い面は、圧縮と解凍の両方に同じコードを再利用できることです。そのため、compressのコードはdecompressのコードとまったく同じですが、先頭に追加があります。~

これにより~、Brachylogに引数の順序を逆にするように指示します(つまり、入力を出力として使用し、出力を入力として使用します)。compressにはnoがあるため~、実際には述語を標準の順序で実行します。解凍には1つしかないため、入力として出力、入力として出力で実行します。

そのようにして、同じコード(modulo that extra ~)を使用して圧縮と解凍の両方を行うことができます:圧縮は入力として2つの文字列を提供し、出力として変数を提供し、解凍は出力としてインデックスと圧縮文字列を提供し、入力として変数を提供します。

明らかに、これは、インタープリターが「逆方向」に実行できるように、圧縮コードについて少し明確にする必要があることも意味します。これが、コンプレッサー自体が少し長い理由です。

Compress(および解凍)のコードの内訳を次に示します。

{……………………………………………………………………}   Call that predicate the normal way (with swapped arguments
                                 for decompress)
   Ċ                           Input has two elements
   ∧Lċ₂l                       L is a string of any length (measuring its length forces it to
                                 take a specific length from 0 to +inf)
   ∧Lgj                        The list [L,L]
       :?z                     The list [[L, First elem of Input],[L,second elem of input]]
          {………………………………}ᵐ:L    Final output is the [M,L] where M is the result of mapping
                                 the predicate below on both elements of the zip
           tT                  The second element of the input is T
           ∧?h~cṪ              Anticoncatenate the first element of the input into [A,B,C]
           hlI                 I = length(A)
           ∧ṪbhTl:I+-₁         J = length(T) + I - 1
           :I↔                 Output = [I,J]

4

ゼリー58 50 バイト

ais523のおかげで-1バイト(2バイト文字列に使用)

これはかなりゴルフに適しているかもしれません...

圧縮は2つの文字列引数を取り、リストを返します。
[[[startA, lengthA], [startB, lengthB]], compressedString]

w³;w⁴$
0;J⁸ḣ;€
ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ,

解凍は、1つの引数(リストなど)を取り、2つの*文字列を返します。

,
⁾ṫḣżFv
Ḣç€Ṫ

重複コード:

w³;w⁴$
0;J⁸ḣ;€
ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ,
⁾ṫḣżFv
Ḣç€Ṫ

ワンインデックス。

*これは、Jellyの暗黙的な印刷フォーマットのために明らかではない場合があるため、上記にリンクされたTryItOnlineのコードにYは、印刷出力の2つの間に改行を挿入するための余分なバイト(末尾)があります。

最初の(または唯一の)引数の深さを使用して圧縮と圧縮解除を決定する単一のプログラムから始めましたが、圧縮解除コード(最初の行)に未使用のリンクがあり、単一のオーバーラップするバイトが7バイト短くなっています。

どうやって?

ç;ç@ÑẠ$ÐfLÐṂṪµ³,⁴L€ż@Ñ, - Compression: stringA, stringB
ç                       - call the last link (2) as a dyad
  ç@                    - call the last link (2) as a dyad with reversed arguments
 ;                      - concatenate (gives all overlapping strings)
       Ðf               - filter keep:
      $                 -     last two links as a monad
    Ñ                   -         call the next link (1) as a monad
     Ạ                  -         All? (no zeros exist in that result)
          ÐṂ            - filter keep with minimal:
         L              -     length
            Ṫ           - tail (for when more than one exists)
             µ          - monadic chain separation (we now have the compressed string)
              ³,⁴       - [stringA, stringB]
                 L€     - length of €ach
                   ż@   - zip with reversed arguments with
                     Ñ  - next link (1) as a monad with the compressed string
                      , - paired with the compressed string

J0;⁸ḣ;€ - Link 2, possible overlaps: stringL, stringR
J       - range(length(stringL)) - [1,2,...,length(stringL)]
 0;     - zero concatenate       - [0,1,2,...,length(stringL)]
   ⁸    - stringL
    ḣ   - head (vectorises)      - [empty string, first char, first two, ..., stringL]
     ;€ - concatenate €ach with stringR

w³;w⁴$ - Link 1, substring indexes: stringX
w³     - first index of first program argument in stringX or 0 if not found
  ;    - concatenated with
     $ - last two links as a monad
   w⁴  -     first index of second program argument in stringX or 0 if not found
Ḣñ€Ṫ - Decompression: [[[startA, lengthA], [startB, lengthB]], compressedString], ?
Ḣ    - head - [[startA, lengthA], [startB, lengthB]]
   Ṫ - tail - compressedString
 ç€  - call the last link (2) as a dyad for €ach of the left list
     -- extra Y atom at TIO joins the resulting list of two strings with a line feed.

⁾ṫḣżFv - Link 2, extract a substring: [start, length], string
⁾ṫḣ    - string "ṫḣ"
   ż   - zip with [start, length] to yield [['ṫ', start],['ḣ', length]]
    F  - flatten, making a list of characters
     v - evaluate as Jelly code with the string as an argument
       - this evaluates as string.tail(start).head(length) yielding the substring

, - Link 1: only here to make an overlap with the compression program.

“ṫḣ”2文字の文字列のJellyの構文を使用して、1バイトずつゴルフをすることができます。

これは答えそのものとはまったく関係のない質問ですが、コードの説明を手で書いていますか、それともコードからコードを生成するツールはありますか?
-tfrascaroli

@tfrascaroli私はそれを手で書く
ジョナサンアラン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.