Golf A括弧マッチングアルゴリズム


25

文字列が与えられますs。文字列[のsと]s が等しく、少なくとも1つあることが保証されます。ブラケットのバランスが取れていることも保証されます。文字列には他の文字を含めることもできます。

目的は、タプルのリストまたは各[および]ペアのインデックスを含むリストのリストを出力/返すことです。

注:文字列はゼロインデックスです。

例: !^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][]返す必要があります

[(8, 41), (20, 33), (21, 27), (36, 39), (42, 48), (49, 50)]またはこれと同等のもの。タプルは必要ありません。リストも使用できます。

テストケース:

input:[[asdf][][td([)ty54g% ]hg[[f]u][f[[jhg][gfd]sdf]sdfs]ghd]fr43f]
output:[(0, 62),(1, 6), (7, 8), (9, 56), (13, 22), (25, 30), (26, 28), (31, 52), (33, 47), (34, 38), (39, 43)]
input:[[][][][]][[][][][[[[(]]]]]))
output:[(0, 9), (1, 2), (3, 4), (5, 6), (7, 8), (10,26),(11, 12), (13, 14), (15, 16), (17, 25), (18, 24), (19, 23), (20, 22)]
input:[][][[]]
output:[(0, 1), (2, 3), (4, 7), (5, 6)]
input:[[[[[asd]as]sd]df]fgf][][]
output:[(0, 21), (1, 17), (2, 14), (3, 11), (4, 8), (22, 23), (24, 25)]
input:[]
output:[(0,1)]
input:[[(])]
output:[(0, 5), (1, 3)]

これはであるため、各プログラミング言語のバイト単位の最短コードが優先されます。


1
出力順序は重要ですか?
wastl

1
いいえ、違います。
ウィンドミルクッキー

21
「注:文字列はゼロインデックスです。」-この種の課題で実装が一貫したインデックスを選択できるようにすることは非常に一般的です(もちろん、あなた次第です)
ジョナサンアラン

1
入力を文字の配列として取得できますか?
シャギー

7
費用は1つのバイト...
dylnan

回答:




5

JavaScript、69 62バイト

電車の中でのちょっとしたゴルフ。おそらく改善することができます。

入力を文字の配列として受け取り、キーが[sのインデックスであり、値が対応する]sのインデックスであるオブジェクトを出力します。

a=>a.map((x,y)=>x==`]`?o[a.pop()]=y:x==`[`&&a.push(y),o={})&&o

オンラインで試す


モバイルでゴルフができるというのは私の心を吹き飛ばします。:P
オリバー

2
@Oliver、それは私がタッチスクリーン上(ちょうど約)タイプできるという私の心を吹くすべてではキーボード戻します- !
シャギー

4

Haskell92 79バイト

g(u:a)n(']':x)=(u,n):g a(n+1)x
g a n(s:x)=g([n|s=='[']++a)(n+1)x
g[]_[]=[]
g[]0

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

説明

g3つの引数を取る関数を作成します。

  • a、これは一致しないすべてのの場所です[

  • n、処理された文字数

  • x これは未処理の文字です。

私たちの最初のキャラクターが前である場合、私たちはフロントから]削除uし、他に残っているものに加えてa戻り(u,n)ます。

g(u:a)n(']':x)=(u,n):g a(n+1)x

最初の文字がでない場合]、それは[何か他のものである場合、インクリメントしての前にn追加[n|s=='[']しますa[n|s=='[']なります[n]場合s=='['[]そうでありません。

g a n(s:x)=g([n|s=='[']++a)(n+1)x

文字が足りない場合は、空のリストを返します。

g[]_[]=[]

1
うわー、再帰関数のいくつかの素晴らしい部分です。私はHaskellの初心者です。これに感銘を受けました:)
ウィンドミルクッキー

@ gnu-nobodyありがとう!この答えはおそらく最適ではないので、ぜひ試してみてください。または、真面目なHaskellゴルファーが到着するまで待つことをお勧めします。
小麦ウィザード

真面目なHaskellゴルファーが到着するまで待つ方が良いでしょう
Windmill Cookies

4

Java 10、95バイト

入力文字列int[]をUnicodeコードポイントとして取得するvoidラムダ。

s->{int r=0,w=0;for(var c:s){if(c==91)s[w++]=r;if(c==93)System.out.println(s[--w]+","+r);r++;}}

オンラインで試す

非ゴルフ

s -> {
    int r = 0, w = 0;
    for (var c : s) {
        if (c == 91)
            s[w++] = r;
        if (c == 93)
            System.out.println(s[--w] + "," + r);
        r++;
    }
}

謝辞

  • 入力文字列をスタックとして使用するというアイデアをくれたJonathan Frechに感謝します(こちら

あなたは定義する必要がありますrし、wコードの一部としてではなく、パラメータとして:s->{int r=0,w=0;...}
オリビエグレゴワール

@OlivierGrégoireちょっとあいまいですが、これは複数の空の入力をカバーすることを意図していたようです。
ヤコブ

1
あなたが引用する答えは、「どこでも使用しない代わり空のパラメータを取ることができますか?」という質問に明示的に答えます。これらの入力を使用しています。ここにはあいまいさはまったくありません。
オリビエグレゴワール

質問の編集部分は、変数の「使用しない」ことについて完全に明確にします。
オリビエグレゴワール

正しいのですが、なぜ(1)入力が未使用であると述べず、(2)余分な入力の値を指定し、(3)余分な入力を悪用する可能性に言及するのはなぜですか?とにかく、変数を移動します。
ヤコブ

4

vim、89バイト

:s/\(.\)/\1<C-V><C-M>/g|g/^\[/ :norm %mm%:pu! =line('.').','.line(\"'m\")<C-V><C-M><C-X>$<C-X>J
:v/\[/d|%s/\[//g

注釈付き

:s/\(.\)/\1<C-V><C-M>/g            " one character per line
|g/^\[/                            " for each opening square bracket:
  :norm %mm%                       "   mark the line with the matching bracket
  :pu! =line('.').','.line(\"'m\") "   write the line numbers to preceeding line
  <C-V><C-M><C-X>$<C-X>J           "   convert to 0-based counting and join lines
:v/\[/d                            " remove all non-opening bracket lines
|%s/\[//g                          " remove brackets

<C-V>0x16です。<C-M>0x0dです。<C-X>0x18です。

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


4

QBasic(QB64)、137 127 112バイト

INPUT a$
for i=0to len(a$)
c$=mid$(a$,i+1,1)
if"["=c$then
b(n)=i
n=n+1
elseif"]"=c$then
n=n-1
?b(n),i
endif
next

私たちは、必要な4つの課題は、0・インデックスを必要とするため、2つのバイトを。私の最初のQBasic投稿、フィードバックを歓迎します。

  • steenberghのおかげで10バイト
  • Erik the Outgolferのおかげで3バイト
  • UNIXファイル形式で保存することで12バイト(\r\n-> \n

実行すると次のようになります。

見た目


良いですね。ポインタのカップル:使用?の代わりには、print(コンパイラこのへを自動展開するprint)、あなたは引用文字列の間にスペースは必要ありませんTHENIFSを、あなたがドロップすることができiた後NEXT
スティーンバーグ

はぁ@steenbergh、私は空白を削除するのを忘れているようだ...しかし、私は間に1つの取り外し0とをto?私は混乱しています
...-wastl

1
わからないQB64について、私が考えるif c$="["になることができif"["=c$elseif c$="]"になることができelseif"]"=c$end ifになることができendif、かつ、出力のわずかな変化で、?b(n),iになることができます?b(n)i(QBasicを1.1私は、あなたのケースは異なる場合があります使用するものです)。
エリックアウトゴルファー

@EriktheOutgolferすべてが、?b(n)i働いていた
wastl

3

Pyth、26バイト

VQIqN\[=+YZ)IqN\],.)YZ)=hZ

ここで試してみてください

説明

VQIqN\[=+YZ)IqN\],.)YZ)=hZ
VQ                     =hZ   For each character in the input (indexed by Z)...
  IqN\[=+YZ)                 ... if the character is [, add the index to Y...
            IqN\],.)YZ)      ... if the character is ], output the previous index
                             and current index.

いいね!私の素朴なアプローチは36バイトC,x"[" MQ #.e*qb\[t+lhfSI/LT"[]"._>Qでした。編集:私はあまりにも私のものにかなりゴルフ、私は今、30を下回るよ成功した
氏Xcoder

3

R141133115112108バイト

function(y,x=utf8ToInt(y)){for(i in seq(x)){if(x[i]==91)F=c(i,F);if(x[i]==93){T=c(T,F[1],i);F=F[-1]}};T[-1]}

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

特にない。私がそう言ったので、1-indexed。Rは、私が最初に使用して、本当に、スタックを持っていないcheadtail同じリテラル効果を得るために。元のバージョンの未ゴルフ(utf8ToIntいくつかのバイトを削除するために更新し、スタックの先頭としてベクターの先頭を使用し、スタックの初期化を避けるために悪用TおよびFビルトインします。):

f <- function(y, x=el(strsplit(y,""))) {
  p <- l <- NULL
  for(i in seq_along(x)) {
    if(x[[i]]=='[') {
      p <- c(p, i)
    }
    if(x[[i]]==']') {
      l <- c(l, tail(p, 1), i)
      p <- head(p, -1)
    }
  }
  l # Because I said so. Change to l-1 if you want to check the test cases.
}


そして、1:nchar(y)よりも短いseq_along(x)。非常に素晴らしいソリューションbtw :)
JayCe

gregexpr行く方法はあるのだろうか。
ngm

私はもともとこのアプローチを活用しようとしましたが、これがここで正しい方法であるかどうかはわかりません。
JayCe

JayCeソリューションに欠陥があります(結果を確認し、22 28 22代わりに戻ります22 28 21)。おそらく、T / Fの(ab)useは本当に安全ではありません:D。これは短く、動作するようです-> オンラインで試してみてください!
digEmAll

2

Forth(gforth)、75バイト

: f 0 do dup i + c@ dup 91 = if i s>f then 93 = if f>s . i . cr then loop ;

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

浮動小数点スタックを乱用しますがdo loop、コードは(手動で)リターンスタックに触れないため、aの使用を許可します。

説明

  1. 文字列内の文字をループする
  2. 各キャラクターを確認する
    1. に等しい場合[、浮動小数点スタックに配置します
    2. ]浮動小数点スタックからポップし、現在位置で出力する場合

コードの説明

0 do                 \ start a loop from 0 to string-length
  dup                \ duplicate the starting address to avoid losing it
  i + c@             \ get the address of the current position and retrieve the character
  dup                \ duplicate the character, to allow checking twice
  91 = if            \ if char = [
    i s>f            \ store the current address on the floating point stack
  then               \ end the if-statement
  93 = if            \ if char = ]
    f>s .            \ pop the starting position from the float-stack and print
    i .              \ print the current position
    cr               \ output a newline
  then               \ end the if-statement
loop                 \ end the loop

2

網膜、36バイト

L$v`\[((\[)|(?<-2>])|[^]])*
$.`,$.>`

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

L

一致結果からリストを生成します。

$

次の置換を使用して、一致の代わりにリストを生成します。

v`

一致が重複することを許可します。

\[((\[)|(?<-2>])|[^]])*

これは、.NETのバランスグループのアプリケーションです。[可能な限り多くの文字が消費された後のように、文字通り一致しています。後続の各[が一致すると、一致が$2スタックに追加されます。そのスタックが空でない場合、スタック]から一致を削除して、a に一致させることができます。それ以外の場合は、a以外のもの][以前に既に一致したもの)に一致させることができます。スタックは(現在)その時点で空である]ため、一致がに一致すると停止[$2ます。

$.`,$.>`

置換は、コンマで区切られた2つの変数で構成されます。.変数の長さは、むしろその値よりも、使用することを示しています。>変数が右側のセパレータではなくマッチの観点から評価されるべきであることを示しています。$`可変手段一致のプレフィックスを指す$.`の位置を与えます[>マッチングの位置を与える試合の権利セパレータのプレフィックスに修正変更し、この]


2

ゼリー 22 21 20  19 バイト

間違いなく、このバイト数の半分でゼリーで可能です:p ...

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä

整数のリストのリストを返す文字のリストを受け入れる単項リンク。
完全なプログラムとして、文字列を受け入れ、そのリストの表現を出力します。

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

どうやって?

n€Ø[ḅ-µMịÄÐƤi€0ĖƊ’Ä - Link: list of characters    e.g. "[f[o]o!]"
  Ø[                - list of characters = ['[', ']']
n€                  - not equal? for €ach              [[0,1],[1,1],[0,1],[1,1],[1,0],[1,1],[1,1],[1,0]]
                    -     ...relating to the characters:  [     f     [     o     ]     o     !     ]
    ḅ-              - convert from base -1             [1,0,1,0,-1,0,0,-1]
                    -     ...i.e.: 1 where '['; -1 where ']'; and 0 elsewhere
      µ             - start a new monadic chain with that as the argument, say V
                Ɗ   - last 3 links as a monad (function of V):
          ÐƤ        -   for post-fixes:
         Ä          -     cumulative sum               [[1,1,2,2,1,1,1,0],[0,1,1,0,0,0,-1],[1,1,0,0,0,-1],[0,-1,-1,-1,-2],[-1,-1,-1,-2],[0,0,-1],[0,-1],-1]
            i€0     -   1st index of 0 in €ach (or 0)  [8,1,3,1,0,1,1,0]
               Ė    -   enumerate                      [[1,8],[2,1],[3,3],[4,1],[5,0],[6,1],[7,1],[8,0]]
       M            - maximal indices of V             [1,3]
        ị           - index into                       [[1,8],[3,3]]
                 ’  - decrement                        [[0,7],[2,2]]
                  Ä - cumulative sum (vectorises)      [[0,7],[2,4]]

私はœ¿それを使用しようとしましたが、それは親relativeですが、解決策を見つけることができませんでした。これは私が得た最も近いものでした。
ディルナン

はい、短くできますが、半分のバイトではなく、たった1バイトしか管理していません。まだ長すぎます。:(
エリック・ザ・アウトゴルファー

@EriktheOutgolferここでも簡単な1バイトのセーブがありました
ジョナサンアラン

2

SWI-Prolog 254バイト

d([']'|T],I,[S|Z],M,R):-J is I+1,d(T,J,Z,[',','(',S,',',I,')'|M],R).
d(['['|T],I,S,M,R):-J is I+1,d(T,J,[I|S],M,R).
d([_|T],I,S,M,R):-J is I+1,d(T,J,S,M,R).
d(_,_,_,R,R).
m(X):-atom_chars(X,A),d(A,0,[],[']'],[_|R]),atomic_list_concat(['['|R],S),print(S).

例:

?- m('!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][]').
'[(49,50),(42,48),(8,41),(36,39),(20,33),(21,27)]'
true 

1

C(gcc)、87バイト

f(char*Z){for(char*z=Z,*q=z;*z;*z++-93||printf("%d,%d;",*--q,z-1-Z))*z-91||(*q++=z-Z);}

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

説明

開き括弧の文字列インデックスを追跡するために、入力文字列は上書きされ、スタックとして使用されます。

f(char*Z){          // take mutable input string
 for(char*z=Z,*q=z; // copy pointer to current string index, current stack index
 *z;                // loop through the entire string
 *z++-93||          // if z == ']'
   printf("%d,%d;", // decrement stack pointer,
    *--q,z-1-Z))    //  write bracket pair position
  *z-91||           // if z == '['
   (*q++=z-Z);}     // write bracket position onto stack, increment stack pointer

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



1

Japt v1.4.5、23バイト

;Ë¥']?ApENo):D¥'[©NpE
A

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

開梱と仕組み

;UmDE{D==']?ApENo):D=='[&&NpE
A

;                              Use alternative set of initial variables
                               A = [] is used here
 UmDE{                         Map over each char of input string...
      D==']?                     If the char is closing bracket...
            ApENo)                 Push the current index and N.pop() to A
                  :D=='[&&       Otherwise, if the char is opening bracket...
                          NpE      Push the current index to N

A     Output A

出力はの平坦化された配列です[closing index, opening index]。逆の順序が望ましくない場合、w最後に追加するとジョブが実行されます(+1バイト)。


1

Common Lisp、95バイト

(lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
ロングバージョン
(defun par (string &aux stack)
  (dotimes (pos (length string))
    (case (char string pos)
      (#\[ (push pos stack))
      (#\] (print (list (pop stack) pos))))))
テスト
((lambda(u &aux s)(dotimes(p(length u))(case(elt u p)(#\[(push p s))(#\](print`(,(pop s),p))))))
 "!^45sdfd[hello world[[djfut]%%357]sr[jf]s][srtdg][] ")

プリント:

(21 27) 
(20 33) 
(36 39) 
(8 41) 
(42 48) 
(49 50)

1

K(ngn / k)38 37バイト

{b@0N 2#,/=(|':+\-/a)b:&|/a:"[]"=\:x}

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

{ } 引数付きの関数 x

"[]"=\:x"["およびのオカレンスの2つのブールリスト"]"

a: 割りあてる a

|/ 2つのリストのブール「または」

& どこ(どのインデックス)がブラケットですか?

b: 割りあてる b

-/1 for "["、-1 for "]"、および0以外の場所のリスト

+\ 部分和

|': ペアワイズ最大値(各要素は前のものと最大化され、初期要素は同じままです)

これは、各文字のブラケットの深さを表します。bインデックスを付けて(並置はインデックス付けされます)、ブラケットについてのみブラケットの深さを取得します。

= "group by"-深さをそれらが発生するインデックスにマッピングする辞書

,/ キーを無視して、辞書の値を連結します

0N 2# 2列の行列(リストのリスト)に変形します

b@b行列の各要素のインデックス


1

ゼリー20 18バイト

@ user202729に1つのバイトのおかげで保存されたことを私に知らせるµ€です)

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’

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

動作させるために数時間これと格闘した後...私はそれがこれほど短くなったことに正直に驚いています:-)

説明

ẹⱮØ[µ³ḣċþØ[_/Ụị)Z’   Main link. Argument: s (string)  '[a[b]c[]][d]'
  Ø[                 Shortcut for the string "[]".
 Ɱ                   For each char in the "[]":
ẹ                      Find the indices of each occurrence in the input.
                     For our example, this gives the array [[1, 3, 7, 10], [5, 8, 9, 12]].

    µ                Begin a new monadic chain, with said array as its argument.
               )     For each of the two sub-arrays q within the array:
                         [[1, 3, 7, 10], [5, 8, 9, 12]]
     ³ḣ                For each item n in q, take the first n chars of the input.
                         [['[',     '[a[',      '[a[b]c[',   '[a[b]c[]]['],
                          ['[a[b]', '[a[b]c[]', '[a[b]c[]]', '[a[b]c[]][d]']]
        þØ[            For each string s in this, and each char c in "[]":
       ċ                 Count the occurrences of c in s.
                         [[[1, 0],  [2, 0],     [3, 1],      [4, 3]],
                          [[2, 1],  [3, 2],     [3, 3],      [4, 4]]]
           _/          Reduce each pair by subtraction. This is the number of open brackets
                         at each position.
                         [[1, 2, 2, 1], [1, 1, 0, 0]]
             U         Sort the indices by their values, using position as a tiebreaker.
                         [[1, 4, 2, 3], [3, 4, 1, 2]]
              ị        Index these values back into q.
                         [[1, 10, 3, 7], [9, 12, 5, 8]]

               )     Start a new monadic chain with the result as its argument.
                Z    Zip; transpose rows and columns.
                         [[1, 9], [10, 12], [3, 5], [7, 8]]
                 ’   Decrement; switch to 0-indexing.
                         [[0, 8], [9, 11], [2, 4], [6, 7]]

1

CJam、25バイト

0q{"[]"#"_ \p_p "S/=~)}/;

驚くほどの競争力-JaptとJellyにのみ負けます[ 編集:炭とスタックス:(]

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

説明

0                          Push 0.
 q                         Push the input.
  {                   }/   For each character in the input:
   "[]"#                     Find index of this character in the string "[]" (or -1 if not found).
                   =         Use this index to choose
        "       "S/            one of the following snippets
                    ~          and execute it:
         _                       If it was 0 ('['), duplicate the number on the stack.
           \p_p                  If it was 1 (']'), print the current number and the one under it.
                                 If it was -1, do nothing.
                     )       Increment the number on top of the stack.
                        ;  Delete the number.


0

Pyth 28  26バイト

{I#.e,t+lhfSI/LT`Y+._>Qk\]

テストスイート。

現時点では、Mnemonicのアプローチよりも長いですが、これを少し下に落とすことができると感じていますV。初期バージョンは36バイトで、多数のバグもありました。

使い方

{I#.e、t + lhfSI / LT`Y + ._> Qk \] –完全なプログラム。STDINから引用符付き文字列Qを取得します。
   .e –列挙マップ。k =反復インデックス、b =現在の要素。
                     > Qk – kより大きいインデックスでQの要素を取得します。
                   ._ –これのすべてのプレフィックスを生成します。
                  + \] –さらに「]」を追加します(一部のエッジケースを処理するため)。
          f – T =現在の要素でこのリストをフィルターします。
              L `Y – str([])の各文字に対して、" [] "...
             / T – ... Tでの発生をカウントします。
           SI –値がますますソートされているかどうかを確認します。
         h –頭。最初の要素を取得します。
       + l –この長さ+ kを取得します。
      t –デクリメント(1ずつ)。
     、–そして、この値をkとペアにします。[i、k]を返します。iは
                             対応する]とkのインデックスは[。
  #–このリストを以下でフィルタリングします。
{I –ペアは重複排除に対して不変です。

{I#.e,t+lhfSI/LT`Y._>Q aaalmost 22のバイト...のための作品
氏Xcoder

0

Perl 5、53バイト

say"$-[0] ".($+[0]-1)while s/\[[^][]*\]/1x length$&/e

として実行しperl -nE '<above code snippet>'ます。stdinを介して入力を受け取ります。

いつものように、問題に対する最適なPerlソリューションは正規表現です。かなり馬鹿げた文字クラス(s/\[[^][]*\]/.../)を使用して、その中にペアを含まないブラケットのペアを一致させようとします。一致が成功した場合、一致したテキストを1何度も何度も数字に置き換えて、誤ってそれらの括弧を再度一致させないようにし、一致のインデックスを出力します。すすぎ、繰り返します。


0

スタックス、13 バイト

é√p(l▓1½\á²ë(

実行してデバッグする

入力スタックを使用して、開いているブレースペアを追跡します。以下にプログラムを展開し、アンゴルフし、コメントを追加します。

F       iterate over input characters
 .][I   get the index of the character in the string "[]", or -1
 ^|cv   skip the rest of this iteration if index was -1
 i~     push the current iteration index to the input stack
 C      skip the rest of this iteration if index was 0
 \      form a pair with the top two items from the input stack
 JP     join with space, and print

これを実行する


0

、20バイト

FLθ≡§θι[⊞υι]«I⊟υ,Iι⸿

オンラインでお試しください!リンクは、コードの詳細バージョンです。説明:

FLθ

入力文字列の長さの暗黙的な範囲でループします。

≡§θι

現在のキャラクターをオンにします。

[⊞υι

の場合[、現在のインデックスを事前定義された配列変数にプッシュします。

]«I⊟υ,Iι⸿

である場合]は、配列変数から最新のインデックスをポップし、それと現在のインデックスをコンマで区切って出力し、新しい行を開始します。代替出力形式は、許容できる場合、いくつかのバイトを節約します]I⟦⊟υιω。2バイトを節約しますが、各インデックスを別々の行に出力し、インデックスのペアを2倍に間隔を空けます。]I⟦⊟υιインデックスを別々の行に出力するだけで、区別が難しくなります。

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