符号付き単項数のリストを解析します


16

単項数は通常、非負の整数のみを表しますが、次のようにすべての整数を表すように拡張できます。

  • 正の整数NはNとして表されます 1ます。5 -> 11111
  • 負の整数-Nは、aの0後にNが続くことで表されます1ます。-5 -> 011111
  • ゼロは次のように表されます 0

0セパレータとして使用すると、これらの数値のリストを明確に表すことができます。

3,-2,0,1
111,011,0,1
111 0 011 0 0 0 1
11100110001

あなたの仕事:符号付き単項数のリストを表す文字列を取得し、それを10進数のリストに変換します。

詳細

入力は、符号付き単項数の完全なリストであると想定できます。特に、プログラムは1)空の入力または2)区切り文字で終わる入力を処理する必要はありません。

各数値の大きさは127を超えないと想定することができます。文字列またはリストの最大サイズを持つ言語では、入力と出力が言語のデータ構造に適合すると想定できますが、アルゴリズムは理論的には任意のサイズ。

プログラムまたは関数は、標準的な方法でI / Oを実行できます。入力は、文字列または文字のリスト、単一文字の文字列、整数、またはブール値です。1およびを表すために任意の2文字を使用でき0ます。あなたが使用していない場合10、使用しているどの文字を指定してください。

出力は、妥当なリスト形式の10進数でなければなりません(特に、数字の間に何らかの区切り文字が必要です)。負の数値はマイナス記号で示す必要がありますが、言語の負の整数の形式が異なる場合はそれも受け入れます。ゼロは、出力で0またはとして表される場合があります-0

テストケース

1 -> 1
0 -> 0 (or -0, and similarly for the other test cases)
011 -> -2
1101 -> 2,1
1100 -> 2,0
11001 -> 2,-1
110001 -> 2,0,1
11100110001 -> 3,-2,0,1
00000001 -> 0,0,0,-1
01111011111111001111111111111110111111111111111100111111111111111111111110111111111111111111111111111111111111111111 -> -4,8,-15,16,-23,42
01111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 -> -127

2
Nitpick:これにはが含まれ'0'sているため、技術的には単項ではありません。しかし、良い挑戦です!
DJMcMayhem

4
@DJMcMayhemニピックへのニトピック:私は技術的には単項とは言いませんでした。これは、私が「署名付き単項」と呼んでいる単項の拡張です。;)
DLosc

@DJMcMayhem IMO、チャレンジは具体的にはセパレーター(0)と負符号プレフィックス(0)が同じですが、数字の途中に負符号を付けることはできないため(182--693-1数字ですか?いいえ、どちらも1111011000101111まったく同じ理由です)。
エリックアウトゴルファー

出力されたリストが入力の逆の順序である場合、それは大丈夫ですか?
DJMcMayhem

「 - 」記号それは使用していますので、十分に技術的に進小数のどちらかではない
Unlambder

回答:


10

Pythonの273 70バイト

入力として文字列を受け取り、Pythonリストの文字列表現を返す関数。ゼロで、両方の表現が可能0-0(それが最後に来るとき):

lambda s:`map(len,s.split('0'))`.replace('0, ','-').replace('--','0,')

説明

  1. split 入力文字列 sゼロ。
  2. 結果リストの各文字列の長さを取得します(を使用map)。

それには長い道のりが必要です。結局、ゼロは区切り文字でした。そして、数値は単項であるため、lenそれらを10進数に変換すると便利です。しかし、今では、区切り文字以外のの使用をすべて台無しにしました0。幸いなことに、区切り文字以外の使用はすべて先行ゼロであったため、区切り文字ゼロの後に来て、長さゼロの文字列('00'.split('0') == ['', '', ''])を提供しました。これらの長さゼロの文字列も0、のためになりましたlen

  1. リストを(「逆引用符」を使用して)文字列に変えると、混乱をより簡単に修正できます。
  2. replace代わりに、その番号に負符号が付いた別の番号の前にある各ゼロ。これにより、0記号としての使用が修正されますが、リテラルのゼロは壊れます。リテラルゼロの前にもセパレータが付いていたため、次の数字で余分なダッシュのペアになりました。
  3. replaceそれぞれが「リスト」の要素に--戻り0ます。

1
PPCGへようこそ!
Steadybox

これは本当に創造的なアプローチです!Pythonを話さない人もあなたの答えを評価できるように、簡単な説明を追加することもできます。
DLosc

@DLosc、ありがとう、バックティックについては知りませんでした。冗長な説明も追加されました。
メルカトル

8

網膜23 21バイト

(.)0
$1 
01
-1
1+
$.&

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

最初のステージは(.)0<newline>$1<space>、任意の文字と一致します0。一致は、スペースが続く最初の文字に置き換えられます。これにより、文字列が個々の数字に分割されます。

2番目のステージで01<newline>-10、のブロックの前1のを-記号に置き換えます。

最後のステージ1+<newline>$.&は、1のすべてのブロックに一致し、それらをグループの長さに置き換えます。

ここでは個々の段の出力との一例です。


非常に素晴らしい-私のアイデアのすべての24のバイトでの時計に思える...
ニール

1
説明を追加してください。私はRetinaを話しません。
ダニエル

@Dopappは説明を追加
OVS

7

Vim、56バイト

:s/\v(0?1*)0?/\1\r/g|%s/0/-/|%s/1*$/\=len(submatch(0))
D

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

私はしばらくの間vimに投稿していません。Vは時々痛みがあるため、私は主にvimを使用しています。のでcount、我々は、後でそれを否定することはできませんので、数を取得するのに最適ですコマンドは、行に0の「ライン上の1つのはどれかを上書きします」。

説明:

これは簡単な方法よりも1バイト短くなります。

:s/\v(0?1*)0?/\1\r/g
:%s/0/-
:%s/1*$/\=len(submatch(0))
D

コマンドチェーンによるものです。これでコマンドが分離されるため、説明に使用します。

:s/                     " Substitute
                        " Search for...
   \v                   "   Enable 'magic'. This determines whether certain atoms require a backslash or not.
                        "   Without it we would have: '\(0\?1*\)0\?', which is 2 bytes longer
      0?                "   An optional 0
        1*              "   Followed by any number of '1's
     (    )             "   (call that group 1)
           0?           "   Followed by another optional 0
             /          " Replace it with...
              \1        "   Subgroup 1
                \r      "   A newline
                  /g    " Do this for every match on the current line.

現在、署名された各単項数は個別の行にあります。例として「11100110001」を使用すると、この時点で次のようになります。

111
011
0
1

:%s/0   " Replace every 0
     /- " With a dash  

:%s/1*$/                    " Replace every run of 1's at the end of a line
        \=len(submatch(0))  " With the length of said run

各マッチの終わりに改行を追加したため、それを実行する前に空の行がありました。これを実行すると、「0」になります(0の「1」の実行に一致したため)。だから私たちは電話するだけですD、この行を削除するて、空白のままにします


あー :%s/1+$/バックスラッシュを必要としない場合は、1バイト短くなります+:(
NieDzejkob

@NieDzejkobなぜそれが短くなるのか分かりません。また、それは次のよう-になります0-0
DJMcMayhem

そのようにして最後の行を削除したかったのです。
NieDzejkob

7

Haskell68 66バイト

f(x:r)|(a,b)<-span(>0)r=([(0-),(1+)]!!x$sum a):[z|_:t<-[b],z<-f t]

オンラインでお試しください!入力をゼロと1のリストとして受け取ります。使用例:f [0,0,0,1,1]yields [0,-2]

説明:

のパターンマッチングは、入力の最初の要素、後続のsの(潜在的に空の)リスト、および残りの入力にf(x:r)|(a,b)<-span(>0)rバインドxします。入力を考えると、我々が得ます、a1b[0,1,1,1,0,0,1]x=0a=[1,1,1]b=[0,0,1]

現在の数は、a否定されたif の合計か、プラス1 ifのx=0合計aですx=1。これはx、否定および増分関数を含むリストにインデックスを付け、結果の関数をの合計に適用することにより実現されますa[(0-),(1+)]!!x$sum a

残りのリストbは空であるか、区切りのゼロと次の数字を含んでいます。リスト内包表記はパターンで[z|_:t<-[b],z<-f t]マッチしようとしbます_:t、それはhead要素を忘れてリストの残りをバインドしtます。もしbこの試合が失敗し、リスト内包の評価さに空である[]再帰のための基本ケースです。それ以外の場合、関数fは再帰的に適用されt、リスト内包表記zはの結果からすべての要素を評価しますf t


3

Wolfram言語(Mathematica)、80バイト

StringCases[#<>"0",x_~~Shortest@y___~~"0":>(If[x=="0",-#,#+1]&)@StringLength@y]&

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

のメカニズムを乱用 StringCases重複するパターンをチェックしないためます。オーバーラップすることなく左から右に検索するため、常に必要な整数のみを取得します。

説明

#<>"0"

最後にゼロを追加します

StringCases

次のすべてのパターンを検索...

x_~~Shortest@y___~~"0"

単一の文字(それを呼び出すx)、可能な限り短いゼロ長またはより長い文字列(それを呼び出すy)、それに続くゼロ。

(If[x=="0",-#,#+1]&)@StringLength@y

一致するパターンに適用:の長さを取りyます。もしxがゼロの、値を否定します。それ以外の場合は、1を増やします。

空の文字列である00ため、これも同様にカバーし、y計算します-0== 0)。


3

Brain-Flak、94(70?)バイト

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>})
{{}<>([{}])(<>)}{}{}([])}{}<>([]){{}({}<>)<>([])}<>

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

これは、実際、脳フレークには驚くほど簡潔です。

コメント付き/読み取り可能なバージョンは次のとおりです。

([])

{

    #Pop the Stack height
    {}

    (
        #If there isn't a leading 0, evaluate to 1...
        {
            (<()>)

            ()
        }

        #Pop the 0
        {}

        #Push a 0 onto the alternate stack
        (<>)
        <>

        #Run of '1's
        {
            #Decrement the alternate stack
            <([{}]<>{})>
            <>
        }

        #And push it here
    )

    #Was there a not leading 0?

    {
        {}

        #Invert the value on the alternate stack
        <>([{}])(<>)
    }

    #Pop 2 zeros
    {}{}


    ([])

}{}<>

#Push stack height
([])

#Reverse the stack
{

    {}

    ({}<>)

    <>([])

}<>

出力を逆にすることができる場合、代わりに70に対してこれを行うことができます。

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>}){{}<>([{}])(<>)}{}{}([])}<>

私のこの先端がある、ほぼこのような状況のための完璧な。しかし、操作を実行する前に(「1」をカウントする)0をプッシュする必要があり、操作はループで発生するため、まったく機能しません。このヒントを利用して思いつく最短の方法は次のとおりです。

([]){{}({(<()>)()}{}(<>)<>{<([{}]<>{})><>})
{{}<>([{}])(<>)}{}{}(<>())<>([])}{}<>{{}({}<>)<>}<>

これも94バイトです。



3

ハスク20 18 17 15 14バイト

Γ~:?Σṁ_Πȯ₀tΣġ/

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

説明

Γ~:?Σṁ_Πȯ₀tΣġ/  Input is a list, say x = [0,1,1,0,0,0,1,1]
            ġ   Group by
             /  division.
                This splits x right before each 0: [[0,1,1],[0],[0],[0,1,1]]
Γ               Deconstruct into head y = [0,1,1] and tail z = [[0],[0],[0,1,1]]
   ?Σṁ_Π        Apply to y:
       Π         Product: 0
   ?Σ            If that is nonzero, take sum of y,
     ṁ_          else take sum of negated elements of y: u = -2
        ȯ₀tΣ    Apply to z:
           Σ     Concatenate: [0,0,0,1,1]
          t      Drop first element: [0,0,1,1]
         ₀       Recurse: [0,2]
 ~:             Tack u to the front: [-2,0,2]

分割は次のように機能します。 ġ/要素の各対の間の引数分割a,bいる/a bfalsyです。 /a bは、反転された引数を持つ除算であるため、でb除算されaます。このプログラムに関連する値は次のとおりです。

  • /1 1 与える 1(真実)ます。
  • /1 0 与える 0(偽)ます。
  • /0 1 与える Inf(正の無限大、真実)。
  • /0 0Any(特別なNaNのような値、偽)を与えます。

3

Acc !! 252 237バイト

N
Count i while _/48 {
Count n while 48/_ {
Write 45
50+N
}
_+49/_*50
Count u while _%50/49 {
_+100-_%50+N
}
_/50-1
Count h while _/200 {
Write _/200+48
_%200+1
}
Count t while _/20+_%2 {
Write _/20+48
_%20-_%2
}
Write _/2+48
Write 9
N
}

を使用し-0ます。タブ文字で区切られた数字を出力し、末尾にタブを付けます。オンラインでお試しください!

実際のアルゴリズムを書き込む時間:20分。10進出力コードのデバッグ時間:45分。:^ P

コメント付き

これらのコメントがコードを非常によく説明しているかどうかはわかりません。作成中の自分へのメモに基づいているため、Acc !! 動作します。さらに説明が必要な場合はお知らせください。明確にするよう努めます。

# We partition the accumulator _ as [number][flag][nextchar]
# [flag] is a 2-value slot and [nextchar] a 50-value slot
# So [nextchar] is _%50, [flag] is _/50%2, [number] is _/100
# [flag] is 1 if we're in the middle of reading a number, 0 if we're between numbers
# It is also used for outputting as decimal (see below)
# Possible input characters are 0, 1, and newline, so [nextchar] is 48, 49, or 10

# Read the first character
N
# Loop while the character we just read is 0 or 1 and not newline
Count i while _/48 {
  # What we do in the loop depends on the combination of [flag] and [nextchar]:
  # 0,48 (start of number, read 0) => write minus sign, [flag] = 1, read another char
  # _,49 (read 1) => increment [number], [flag] = 1, read another char
  # 1,48 (middle of number, read 0) => write/clear [number], status = 0, read another
  #      char
  # 1,10 (middle of number, read <cr>) => ditto; the next read will be 0 for eof, which
  #      means the acc will be less than 48 and exit the loop

  # Process leading 0, if any
  Count n while 48/_ {
    # acc is 48: i.e. [number] is 0, [flag] is 0, [nextchar] is 48 (representing a 0)
    # Output minus sign
    Write 45
    # Set [flag] to 1 (thereby exiting loop) and read [nextchar]
    50+N
  }
  # If number starts with 1, then we didn't do the previous loop and [flag] is not set
  # In this case, acc is 49, so we add (50 if acc <= 49) to set [flag]
  _+49/_*50

  # Process a run of 1's
  Count u while _%50/49 {
    # [nextchar] is 49 (representing a 1)
    # Increment [number] and read another
    _+100-_%50+N
  }

  # At this stage, we know that we're at the end of a number, so write it as decimal
  # This is "easier" (ha) because the number has at most three digits
  # We shift our partitioning to [number][flag] and set [flag] to 0
  _/50-1

  # Output hundreds digit if nonzero
  # Since [number] is _/2, the hundreds digit is _/200
  Count h while _/200 {
    Write _/200+48
    # Mod 200 leaves only tens and units; also, set [flag] to 1
    _%200+1
  }
  # Output tens digit (_/20) if nonzero OR if there was a hundreds digit
  # In the latter case, [flag] is 1
  Count t while _/20+_%2 {
    Write _/20+48
    # Mod 20 leaves only units; clear [flag] if it was set
    _%20-_%2
  }
  # Write units unconditionally
  Write _/2+48

  # Write a tab for the separator
  Write 9
  # Read another character
  N
}



2

ゼリー 19  18 バイト

より良い方法があるはずです...

®ḢN$Ḣ©?ṄEȧ
ṣ0L€ÇL¿

各番号を印刷する完全なプログラムの後に改行が続きます。

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

どうやって?

®ḢN$Ḣ©?ṄEȧ - Link 1, print first number and yield next input: list of numbers, X
           -                              e.g. [8,0,15,16,...] or [0,4,8,0,15,16,...]
      ?    - if...
    Ḣ      - condition: yield head and modify  8([0,15,16,...])   0([4,8,0,15,16,...])  
     ©     -            (copy to register)     8                  0
®          - then: recall from the register    8
   $       - else: last two links as a monad:
 Ḣ         -         yield head and modify                        4([8,0,15,16,...])
  N                  negate                                      -4
       Ṅ   - print that and yield it           8                 -4
        E  - all equal (to get 0 to be truthy) 1                  1
         ȧ - AND the (modified) input          [0,15,16,...]      [8,0,15,16,...]
           -   (ready to be the input for the next call to this link)

ṣ0L€ÇL¿ - Main link: list e.g. [0,1,0,0,0,0,1,1]
ṣ0      - split at zeros       [[],[1],[],[],[],[1,1]
  L€    - length of €ach       [0,1,0,0,0,2]
      ¿ - while...
     L  - condition: length                           1  1  1  0  ([0,1,0,0,0,2], [0,0,0,2], [0,2], [])
    Ç   - action: call the last link (1) as a monad  -1  0 -2     ( - 1            - 0        - 2)

1

QBasic、88 86バイト

1u$=INPUT$(1)
z=u$<"1
IF n*z THEN?(1-2*s)*(n-s):s=0:n=0ELSE s=s-z:n=n+1
IF"!"<u$GOTO 1

これは楽しかったです。107バイトバージョンから始まる複数のリビジョンは、私が今まで書いたと思うQBasicの最も難読化されたビットの1つをもたらしました。(編集:奇妙なことに、コードを明確にすることで2バイトをゴルフできました。)

注:このプログラムは、画面にエコーせずに一度に1文字ずつユーザー入力を読み取ります(INPUT$(1)通常のINPUTステートメントの代わりに使用した結果)。したがって、入力中は1と0は表示されませんが、計算された10進数が表示されます。必ずヒットするEnter入力の最後でして、最後の数字を確認し、プログラムを終了してください。

ゴルフされていないバージョン

sign = 0
num = 0
DO
  digit$ = INPUT$(1)
  isZero = (digit$ < "1")
  IF num > 0 AND isZero THEN
    PRINT (1 - 2 * sign) * (num - sign)
    sign = 0
    num = 0
  ELSE
    IF isZero THEN sign = 1
    num = num + 1
  END IF
LOOP WHILE "!" < digit$

説明

(別名「何??それでも意味がありません!」)

基本的な戦略は、INPUT$(1)毎回1文字を取得して処理を行うループを実行し、その文字のASCII値!が改行値より大きい(つまり、改行ではない)限りループを続けることです。

2つの変数を使用して、進行中の数値を追跡します。num現在の符号付き単項数の文字数(先行ゼロを含む)。signある1数は、先行ゼロを持っている場合0ではない場合。これらの両方を初期化する必要があります0。QBasicの数値変数は自動的に初期化されるため、ゴルフバージョンに最適です0

私たちは、文字を読むたびに、まず最初に、それはだかどうかを判断することです10。この結果は2回使用するため、に保存しisZeroます。技術的には、その名前は誤解を招く可能性があります。これは、文字が改行の場合も値が真実だからです。QBasicの-1真実はfalseであることに注意してください0

ここで、数値の読み取り中(num > 0)にゼロまたは入力の終わり(isZero)に達した場合、読み取りが終了した数値を計算する必要があります。

  • sign0正の場合1、負の場合に格納します。1ポジティブと-1ネガティブを得るには、が必要1-2*signです。
  • num正の場合は正しい大きさを格納しますが、負の場合は大きさよりも1つ大きくなります(符号マーカーが含まれるため)。だから私たちはnum-signその規模に使用できます。

これらを掛け合わせて印刷します。次にリセットsignnum0、次の番号を読む準備をします。

そうでない場合(ゼロにヒットしていない場合、または数字の先頭にゼロにヒットしている場合)、更新signnumて次のようにします。

  • sign1先行ゼロを見ている場合になります。それ以外の場合、1つを見ていると、それは既にあったものにとどまります。ゴルフされたコードはでs=s-z、これは同じことです:
    • これが先行ゼロの場合、zです-1。であることsが保証されている0ため(これは新しい番号の開始であるため)、にs-zなります1
    • これが1つの場合、zです0。その後s-zs以前の値にとどまります。
  • num インクリメントされます。

それでおしまい!


0

JavaScript(ES6)、60バイト

スペースで区切られた整数のリストを返します。

s=>(0+s).replace(/00?1*/g,s=>(l=s.length,+s[1]?l-1:2-l)+' ')

テストケース


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