부호있는 단수 목록 분석


16

단항 숫자는 일반적으로 음이 아닌 정수만 나타내지 만 다음과 같이 모든 정수를 나타내도록 확장 할 수 있습니다.

  • 양의 정수 N은 N으로 표시됩니다 1.5 -> 11111
  • 음의 정수 -N은 0뒤에 N 으로 표시됩니다 1.-5 -> 011111
  • 0은 다음과 같이 표현됩니다 0

그런 다음 0구분자로 사용하면 이러한 숫자의 목록을 명확하게 나타낼 수 있습니다 .

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

당신의 작업 : 그런 부호있는 단항 목록을 나타내는 문자열을 가져 와서 십진수 목록으로 변환하십시오.

세부

입력이 부호있는 단항 숫자의 전체 목록이라고 가정 할 수 있습니다. 특히, 프로그램은 1) 빈 입력 또는 2) 구분자로 끝나는 입력을 처리 할 필요가 없습니다.

각 숫자의 크기가 127을 초과하지 않는다고 가정 할 수 있습니다. 최대 크기의 문자열 또는 목록을 가진 언어의 경우 입력 및 출력이 언어의 데이터 구조에 적합하다고 가정 할 수 있지만 알고리즘은 이론적으로 어떤 크기.

프로그램이나 기능은 표준 방법으로 I / O를 수행 할 수 있습니다 . 입력은 문자열 또는 문자 목록, 단일 문자 문자열, 정수 또는 부울 일 수 있습니다. 당신은 표현하기 위해 두 문자를 사용할 수 있습니다 10; 사용하지 않는 경우 10, 당신이 사용중인 문자를 지정하십시오.

출력은 합리적인 목록 형식의 10 진수 여야합니다 (특히 숫자 사이에 일종의 구분 기호가 있어야 함). 음수는 빼기 부호로 표시해야합니다. 언어가 음수 정수의 형식이 다른 경우에도 허용됩니다. 출력에서 0은 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 Nitpick nitpick에 : 기술적으로 단항하다고 말한 적이 없습니다. 이것은 "서명 된 단항"이라고 부르는 단항확장입니다 . ;)
DLosc

@DJMcMayhem IMO의 과제는 특히 구분 기호 ( 0)와 음수 접두사 ( 0)가 동일하지만 숫자 중간에 음수 부호를 가질 수 없기 때문에 여전히 명확하지는 않습니다 ( 182--693-1숫자입니까? 1111011000101111똑같은 이유 도 아닙니다 ).
Outgolfer Erik

출력 된 목록이 입력의 순서와 반대이면 괜찮습니까?
DJMcMayhem

'-'기호가를 사용하기 때문에 잘 기술적으로 소수 소수 중 하나없는
Unlambder

답변:


10

파이썬 2 , 73 70 바이트

문자열을 입력으로 받아 Python 목록의 문자열 표현을 반환하는 함수입니다. 제로 모두에 의해 표현 될 수 0-0(이것은 마지막 때) :

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

설명

  1. splits0 의 입력 문자열
  2. 결과 목록에서 각 문자열 의 길이 를 사용하십시오 (를 사용하여 map).

그것은 우리에게 먼 길을 걸립니다. 결국 0은 분리 자였습니다. 그리고 숫자는 단항 이었으므로 len편리하게 숫자 를 십진수로 변환합니다. 그러나 이제 우리는 분리자가 아닌 모든 사용법을 망쳤습니다 0. 운 좋게도 모든 비분 리자 사용은 선행 제로이므로 분리 자 0 다음에 왔으며 길이가 0 인 문자열 ( '00'.split('0') == ['', '', ''])을 제공했습니다. 길이가 0 인 문자열도로 0인해 되었습니다 len.

  1. 리스트를 문자열로 바꾸면 ( "reverse quotes"사용 ) 엉망진창을보다 쉽게 ​​고칠 수 있습니다.
  2. replace다른 숫자 앞에 오는 각 0은 해당 숫자에서 음수 부호로 대체됩니다. 0부호 의 사용을 수정 하지만 리터럴 0을 끊습니다. 리터럴 제로 앞에는 구분 기호가 추가되었으므로 이제 다음 숫자에서 추가 대시 쌍이되었습니다.
  3. replace각각 "목록" --0요소 로 되돌아갑니다 .

1
PPCG에 오신 것을 환영합니다!
Steadybox

이것은 정말 창의적인 접근법입니다! 파이썬을 구사하지 못하는 사람들이 당신의 답변에 감사 할 수 있도록 짧은 설명을 추가하고 싶을 수도 있습니다.
DLosc

@DLosc, 고마워, 나는 백틱에 대해 몰랐다. 경건한 설명도 추가되었습니다.
mercator

8

망막 , 23 21 바이트

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

온라인으로 사용해보십시오!

첫 번째 단계 (.)0<newline>$1<space>는 뒤에 모든 문자를 찾습니다 0. 일치는 첫 번째 문자와 공백으로 대체됩니다. 이렇게하면 문자열이 개별 숫자로 분할됩니다.

두 번째 단계의 01<newline>-1대체합니다 0'의 블록 전에들 1'은에에이야 -기호.

마지막 단계 1+<newline>$.&는의 모든 블록을 일치 1시키고 그룹의 길이로 대체합니다.

다음 은 개별 단계의 출력 예입니다.


아주 좋은-내 모든 아이디어는 24 바이트에서 시계에 보이는 것 같습니다 ...
Neil

1
설명을 추가해 주시겠습니까? 나는 레티 나를 못해요.
Daniel

@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우리가 나중에 그것을 부정하지 수의 수를 얻기위한 완벽한 명령은, 라인에 공의 '라인에 하나의 어떤을 덮어 쓰게됩니다'.

설명:

이것은 간단한 방법보다 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

마지막 줄을 그런 식으로 제거하고 싶었습니다 .P, 신경 쓰지 마십시오.
NieDzejkob

7

하스켈 , 68 66 바이트

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

온라인으로 사용해보십시오! 0과 1의 목록으로 입력을받습니다. 사용법 예 : f [0,0,0,1,1]yields [0,-2].

설명:

패턴 일치 f(x:r)|(a,b)<-span(>0)rx 는 입력의 첫 번째 요소, a다음 1의 (잠재적으로 비어있는) 목록 및 b나머지 입력 바인드 됩니다 . 입력을 감안할 때 [0,1,1,1,0,0,1], 우리는 수 x=0, a=[1,1,1]b=[0,0,1].

현재 숫자는 다음의 합입니다 a 부정 if x=0의 합이거나 a더하기 if 의 합입니다 x=1. 이것은로 인덱싱함으로써 달성된다 x부정 및 증가 함수를 포함하는리스트에, 그리고 합계 생성 함수를 적용 a: [(0-),(1+)]!!x$sum a.

나머지 목록 b은 비어 있거나 분리 된 0과 다음 숫자를 포함합니다. 리스트 이해 [z|_:t<-[b],z<-f t]b패턴 _:t에서 일치 를 시도합니다. 즉 head 요소를 잊고 나머지리스트를 바인드합니다 t. 경우 b실패이 경기와의 지능형리스트 평가하여 비어있는 []재귀의 기본 케이스입니다. 그렇지 않으면 함수 f가 재귀 적으로 적용되고 t목록 이해 z가의 결과에서 모든 요소 로 평가됩니다 f t.


3

볼프람 언어 (수학) , 80 바이트

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

온라인으로 사용해보십시오!

의 기계를 남용 StringCases 패턴을 겹치지 않기 때문에 . 겹치지 않고 왼쪽에서 오른쪽으로 검색하기 때문에 항상 필요한 정수만 얻습니다.

설명

#<>"0"

끝에 0을 추가

StringCases

다음 패턴을 모두 찾으십시오.

x_~~Shortest@y___~~"0"

단일 문자 (콜백 x) 다음 가능한 가장 짧은 길이 또는 길이가 긴 문자열 (콜백 y) 다음에 0이옵니다.

(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 (무한대, truthy).
  • /0 0제공 Any(특수 값 할머니처럼, falsy).

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 분 내 십진수 출력 코드를 디버깅하는 시간 : 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

Q 기본, 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에서 가장 난독 화 된 비트 중 하나를 작성했습니다.(편집 : 이상하게도 코드를 명확하게하여 2 바이트를 골프화 할 수있었습니다.)

참고 :이 프로그램은 사용자 입력을 한 번에 한 문자 씩 화면에 표시하지 않고 읽습니다 ( 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)매번 하나의 문자를 가져 와서 처리하고, 문자가 ASCII 값보다 큰 ASCII 값을 갖는 한 계속 반복 하는 루프를 실행하는 것입니다.! (즉, 줄 바꿈이 아닌) .

우리는 두 가지 변수를 사용하여 진행중인 숫자를 추적합니다. num현재 부호있는 단항 숫자 (앞의 0을 포함)의 문자 수입니다. sign1수, 앞에 0이 있다면 0하지 않을 경우. 0QBasic의 숫자 변수는로 자동 초기화되기 때문에이 두 가지 모두로 초기화해야 0합니다.

문자를 읽을 때마다 가장 먼저 문자인지 1또는 문자인지를 결정해야합니다 0. 이 결과를 두 번 사용하므로에 저장합니다 isZero. 기술적으로, 그 이름은 문자가 개행 문자이면 가치가 진실하기 때문에 오해의 소지가 있습니다. QBasic에서 -1진실은 거짓이고 거짓은 그렇습니다 0.

이제 숫자 ( num > 0) 를 읽는 도중에 0 또는 입력 끝 ( isZero)에 도달하면 읽은 숫자를 계산해야합니다.

  • sign0긍정, 1부정을 위해 저장 합니다 . 1긍정적이고 -1부정적인 것을 얻으려면 , 우리는 필요합니다 1-2*sign.
  • num(양수 표시를 포함하므로) 양수에 대한 정확한 크기를 제외하고 음수에 대한 크기보다 하나 더 저장합니다. 따라서 우리는 num-sign규모에 사용할 수 있습니다 .

이것들을 곱하고 인쇄하십시오; 다음 재설정 signnum0다음 숫자를 읽기위한 준비.

그렇지 않으면 (우리는 0을 명중하지 않았거나 우리가 숫자의 시작 부분에 0을 공격 한 경우 경우), 우리는 업데이트 signnum같은 다음과 같습니다 :

  • sign하게 1우리가이 앞에 0이보고있는 경우; 그렇지 않으면, 우리가 하나를보고 있다면, 그것은 이미 있던 것에 머물러 있습니다. 골프 코드는 s=s-z다음과 같습니다.
    • 이 값이 앞에 오는 0이면 z입니다 -1. 이후 s로 보장됩니다 0(이것은 새로운 번호의 시작이기 때문에) s-z될 것입니다1 .
    • 이것이 하나 인 경우 z입니다 0. 그런 다음 이전에 가졌던 s-z가치를 유지 s합니다.
  • num 증가합니다.

그게 다야!


0

자바 스크립트 (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.