Hãy thực hiện chế độ ăn kiêng Haskell


21

Haskell có các bộ dữ liệu có thể được viết là

(a,b,c)

Tuy nhiên đây chỉ là cú pháp đường cho

(,,)a b c

Nói chung, một tuple n có thể được hình thành với n-1 , s giữa (... )theo sau là các phần tử của nó được phân tách bằng khoảng trắng. Ví dụ: 7-tuple, (1,2,3,4,5,6,7)có thể được hình thành bởi

(,,,,,,)1 2 3 4 5 6 7

Vì Haskell không có 1 tuple nên chúng không thể được hình thành. Bạn cũng sẽ không chịu trách nhiệm cho các bộ dữ liệu trống.

Các bộ dữ liệu lồng nhau có thể được hình thành bằng cách sử dụng parens để ghi đè thứ tự các thao tác.

((1,2),3) == (,)((,)1 2)3

Là một phần trong nỗ lực của chúng tôi để loại bỏ tất cả đường cú pháp khỏi Haskell, tôi sẽ đề nghị bạn viết một chương trình loại bỏ đường cú pháp khỏi các bộ dữ liệu của Haskell.

Chương trình của bạn nên lấy một tuple, một mảng hoặc một chuỗi đại diện cho một tuple có đường và sẽ xuất ra một chuỗi đại diện cho một tuple "không đường". Các bộ dữ liệu đầu vào sẽ chỉ bao gồm các số nguyên dương hoặc các bộ dữ liệu khác.

Vì chúng tôi đang chơi golf ở đây nên đầu ra của bạn phải ngắn. Nó không nên chứa không cần thiết

  • Không gian. Không gian chỉ nên được sử dụng để phân tách các đối số của hàm tuple và không xuất hiện sau một )hoặc trước một(

  • Dấu ngoặc đơn. Chỉ nên sử dụng dấu ngoặc đơn khi hình thành các hàm tuple hoặc khi các bộ dữ liệu lồng nhau.

Đây là một câu hỏi vì vậy câu trả lời sẽ được ghi bằng byte với ít byte hơn sẽ tốt hơn.

Các trường hợp thử nghiệm

(1,2)     -> (,)1 2
(1,2,3)   -> (,,)1 2 3
((1,2),3) -> (,)((,)1 2)3
(1,2,3,4) -> (,,,)1 2 3 4
(1,(2,3)) -> (,)1((,)2 3)
(10,1)    -> (,)10 1

Nếu tôi không thiếu thứ gì, bạn bao gồm 1 tuple nhưng không trống tuples ..? Là tuples trống đầu vào hợp lệ?
hoàn toàn là

3
@totallyhuman Bạn không phải xử lý các bộ dữ liệu trống.
Thuật sĩ lúa mì

Trường hợp thử nghiệm thứ 5 có thêm,
H.PWiz

2
Cũng bởi "số", bạn có nghĩa là "số nguyên dương"?
Erik the Outgolfer

2
Các trường hợp thử nghiệm được đề xuất: ((1,(2,3)),4,(5,6))(1,(2,3),4).
Ørjan Johansen

Câu trả lời:


17

Haskell , 169 148 byte

init.tail.fst.([]%)
p:k="(,"
l%('(':r)|(y,x:s)<-[]%r,m<-y:l=last$m%(p:s):[(p:p:(l>>k)++x:foldl(\r x->x++[' '|x>k,r>k]++r)[x]m,s)|x<',']
l%r=lex r!!0

Hãy thử trực tuyến! Lấy tuple như một chuỗi. init.tail.fst.([]%)là chức năng chính ẩn danh. Ràng buộc nó để ví dụ fvà sử dụng như thế f "(3,(14,1),4,7)", mà mang lại "(,,,)3((,)14 1)4 7".

Tại sao đầu vào không được cung cấp dưới dạng bộ dữ liệu Haskell, bạn yêu cầu? Bởi vì Haskell được gõ mạnh, một tuple (1,2)có loại (Int,Int)1 và một tuple (1,(2,3))có loại (Int,(Int,Int)). Do đó, một hàm chấp nhận loại tuple thứ nhất không thể được áp dụng cho loại thứ hai, và đặc biệt là không thể có chức năng nào lấy một tuple 2 tùy ý .

Giải trình:

  • p:k="(,"là một cách ngắn để gán pcho '('kđến ",".
  • (%)là chức năng phân tích cú pháp và chuyển đổi đệ quy. Đối số đầu tiên là danh sách các mục nhập đã được phân tích cú pháp, đối số thứ hai là phần còn lại của chuỗi gốc. Mỗi cuộc gọi trả về một bộ dữ liệu được chuyển đổi hiện tại (dưới dạng một chuỗi và được đặt trong ngoặc) và phần còn lại của chuỗi.
    • l%('(':r)Nếu chuỗi bắt đầu bằng một dấu ngoặc mở, chúng ta cần phân tích một mục nhập tuple mới.
      (y,x:s)<-[]%rChúng tôi áp dụng đệ quy %và nhận một mục nhập tuple yvà chuỗi còn lại được chia thành ký tự tiếp theo xvà phần còn lại của chuỗi s.
      m<-y:lChúng tôi thêm mục mới vào ydanh sách hiện tại của các mục đã tìm thấy lvà gọi kết quả m.
    • Ký tự tiếp theo xbây giờ là dấu phẩy ,hoặc dấu ngoặc đóng ). Đây last$ <B> :[ <A> |x<',']chỉ là một cách viết ngắn hơn if x == ')' then <A> else <B>.
    • Vì vậy, nếu a ,là tiếp theo, chúng ta cần phân tích đệ quy mục tiếp theo: m%(p:s)Chúng tôi đặt trước một dấu ngoặc mở để kết thúc trong trường hợp đúng và vượt qua danh sách các mục đã tìm thấy m.
    • Nếu không x == ')', chúng ta đã hoàn thành bộ dữ liệu hiện tại và cần thực hiện chuyển đổi cần thiết:(p:p:(l>>k)++x:foldl(\r x->x++[' '|x>k,r>k]++r)[x]m,s)
      • p:p:(l>>k)++x:Nếu chúng ta đã tìm thấy n mục, thì mn phần tử và y, danh sách trước khi thêm phần tử được tìm thấy gần đây nhất, có n-1 mục. Điều này rất hữu ích khi chúng ta cần n-1 , cho một nbộ phần tử và l>>khoạt động trên các danh sách dưới dạng "nối danh sách kvới chính nó nhiều lần ycó các phần tử" . Do đó phần đầu tiên này mang lại một số chuỗi như "((,,,)".
      • foldl(\r x->x++[' '|x>k,r>k]++r)[x]mnối các phần tử của m(theo thứ tự ngược lại, bởi vì bằng cách thêm các mục mới vào mchính mặt trước đã được xây dựng theo thứ tự ngược lại) trong khi chỉ thêm khoảng trắng ở giữa hai phần tử nếu cả hai đều là số: [' '|x>k,r>k]chúng tôi kiểm tra xem các mục hiện tại xrlà số bằng cách so sánh theo từ vựng chúng đến ","- nếu chúng không phải là số, chúng đã là một đại diện bộ dữ liệu được đặt trong ngoặc và '(' < ','giữ.
    • Nếu mẫu khớp với l%('(':r)ngay từ đầu không thành công, thì chúng ta sẽ ở dòng cuối cùng : l%r=lex r!!0. Điều này có nghĩa là chúng ta cần phân tích một số và trả về số đó và phần còn lại của chuỗi. May mắn thay, có lexchức năng thực hiện chính xác điều đó (Nó phân tích mã thông báo Haskell hợp lệ tiếp theo, không chỉ là số). Tuy nhiên, bộ kết quả được gói vào một danh sách, vì vậy chúng tôi sử dụng !!0để lấy phần tử đầu tiên của danh sách.
  • init.tail.fst.([]%)là hàm chính lấy một chuỗi và áp dụng %với một danh sách trống cho nó. Ví dụ, đối với một đầu vào "(1,2)", áp dụng ([]%)sản lượng ("((,)1 2)",""), do đó, bộ dữ liệu bên ngoài và dấu ngoặc cần phải được loại bỏ. fstlấy phần tử đầu tiên của bộ dữ liệu, tailloại bỏ khung đóng và initphần mở.

Chỉnh sửa: Rất cám ơn @ janrjan Johansen vì đã chơi golf tổng cộng 21 byte !


1 Trên thực tế, loại là (Num t1, Num t) => (t, t1) , nhưng đó là một câu chuyện khác nhau.

2 Bỏ qua các hàm đa hình như id , không thể thực sự hoạt động với đầu vào của chúng.


1
Người ta có thể viết một hàm đa hình bằng cách sử dụng một kiểu chữ Desugarable, nhưng người ta sẽ phải khai báo các thể hiện cho Inttất cả các kiểu tuple.
Bergi

1
gcó thể được rút ngắn foldr1(\x r->x++[' '|x>k,r>k]++r)và nội tuyến.
Ørjan Johansen

@Bergi: Khác và người ta không thể khai báo các thể hiện cho tất cả các loại tuple . :-) (Thử: show (1,2,3,4,5,6,7,8,9,0,1,2,3,4,5)trong GHCi, sau đó thêm một ,6ở cuối và thử lại.)
wchargein

1
Cải thiện nội tuyến cho thêm sáu byte: Sử dụng m<-y:l, gập sang trái thay vì phải và sử dụng [x]làm giá trị ban đầu. Hãy thử trực tuyến!
Ørjan Johansen

1
fcó thể ẩn danh : init.tail.fst.([]%).
Ørjan Johansen

11

Haskell, 141 byte138 byte (Cảm ơn Ørjan Johansen)

import Language.Haskell.TH
f(TupE l)='(':tail(","<*l)++')':""%l
q%(LitE(IntegerL i):l)=q++show i++" "%l
_%(e:l)='(':f e++')':""%l
_%[]=[]

fcó loại Exp -> String.

  • Đầu vào: một mô hình Haskell mẫuExp (nghĩa là biểu diễn AST tiêu chuẩn của các giá trị Haskell loại tùy ý - về cơ bản, đã phân tích mã Haskell trước khi kiểm tra loại); phải đại diện cho một bộ dữ liệu chỉ chứa các số nguyên không âm và các bộ dữ liệu khác.

  • Đầu ra: một chuỗi chứa cú pháp desugared cho biểu thức tuple đó.

Bản giới thiệu:

$ ghci TupDesugar.hs 
GHCi, version 8.3.20170711: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Loaded GHCi configuration from /home/sagemuej/.ghci
[1 of 1] Compiling Main             ( TupDesugar.hs, interpreted )
Ok, 1 module loaded.
*Main> :set -XTemplateHaskell -XQuasiQuotes
*Main> f <$> runQ [|(1,2)|]
"(,)1 2"
*Main> f <$> runQ [|(1,2,3)|]
"(,,)1 2 3"
*Main> f <$> runQ [|((1,2),3)|]
"(,)((,)1 2)3"
*Main> f <$> runQ [|(1,2,3,4)|]
"(,,,)1 2 3 4"
*Main> f <$> runQ [|(1,(2,3))|]
"(,)1((,)2 3)"
*Main> f <$> runQ [|(10,1)|]
"(,)10 1"

2
Bạn có thể thay đổi ")"++thành ')':hai nơi và tiết kiệm không gian sau khi taildi chuyển nó ra ngoài dấu ngoặc đơn.
Ørjan Johansen

7

Haskell , 119 byte

data T=I Int|U[T]
f(U t)="(("++init(t>>",")++')':foldr(\x y->f x++[' '|f x>",",y>","]++y)")"t
f(I n)=show n
init.tail.f

Hãy thử trực tuyến! Điều này sử dụng một loại dữ liệu tùy chỉnh Tđể đại diện cho các bộ dữ liệu , đó là một bộ dữ liệu ((1,2),3)được biểu diễn dưới dạng U[U[I 1,I 2],I 3]. Ví dụ sử dụng: init.tail.f $ U[U[I 1,I 2],I 3]sản lượng (,)((,)1 2)3.



4

GNU sed, 149 82 + 2 = 84 byte

+2 byte cho -rcờ.

y/(),/<>'/
:
s/([^<>']+)'/,\1 /
t
s/ ?<(,+)([^>]+)>/((\1)\2)/
t
s/^.|(\)) |.$/\1/g

Hãy thử trực tuyến!

Giải trình

y/(),/<>'/                   # Replace parens and commas with brackets and apostrophes
:
  s/([^<>']+)'/,\1 /.          # Remove each apostrophe and insert comma after <
  t                            # Branch to : if substitution was made
  s/ ?<(,+)([^>]+)>/((\1)\2)/  # Change <,,,...> to ((,,,)...)
  t                            # Branch to : if substitution was made
s/^.|(\)) |.$/\1/g           # Remove outermost ()s and extra spaces

Điều này thất bại trên một số trường hợp phức tạp hơn: ((1,(2,3)),4,(5,6))(1,(2,3),4).
Ørjan Johansen

@ RjanJohansen Bắt tốt. Tôi sẽ xem xét sau khi ăn sáng.
Jordan

3

JavaScript, 75 byte

f=a=>`(${t=a.map(x=>'')})${a.map(v=>t=1/v?1/t?' '+v:v:`(${f(v)})`).join``}`

Mảng đầu vào của số | mảng, chuỗi đầu ra.

Nhờ Neil, lưu 2 byte


(1/t?' ':0)+vcó thể 1/t?' '+v:v.
Neil

2

Toán học, 94 byte

{"(",","&/@Most@#,")",c=1>0;(xIf[j=ListQ@x,c=j;"("<>#0@x<>")",If[c,c=j;x," "<>x]])/@#}<>""&

Chứa một chức năng U+F4A1dựng sẵn không thể in được Function.

Mất một Listsố nguyên Strings. Nếu điều này là không được phép, điều này có thể được cố định bằng cách thêm 10 byte (phiên bản này có một Listsố Lists / Integers):

{"(",","&/@Most@#,")",c=1>0;(xIf[j=ListQ@x,c=j;"("<>#0@x<>")",If[c,c=j;""," "]<>ToString@x])/@#}<>""&

2

Pip , 45 byte

{Y"()"b:yJ',X#a-1Fcab.:c>0?s.cyJ(fc)bR") "')}

Đây là một hàm lấy danh sách làm đối số. Hãy thử trực tuyến!

Phiên bản đã bình luận

; Define an anonymous function (the argument is available inside as the variable a)
{
  ; Yank the string "()" into y variable
  Y "()"
  ; Create a string of len(a)-1 commas, join y on it, and assign to b
  b: y J ',X#a-1
  ; For each item c in a
  F c a
    ; Concatenate to b the following expression
    b .:
      ; Is c integer or list?
      ; (If c is a positive integer, c>0 is true; but if c is a list, c>0 is false)
      c>0 ?
        ; If c is integer, concatenate space followed by c
        s.c
        ; If c is list, call function recursively on c and use the result to join y
        yJ(fc)
  ; Replace ") " with ")" in b and return the resulting string
  b R ") " ')
}

2

JavaScript (ES6), 88 84 byte

f=a=>a.reduce((s,e)=>s+=e[0]?`(${f(e)})`:/\)$/.test(s)?e:' '+e,`(${[...a].fill``})`)

Có một mảng các số nguyên và mảng. Chỉnh sửa: Đã lưu 1 byte bằng cách sử dụng s+=thay vì hai lần sử dụng riêng biệt s+. Đã lưu thêm 3 byte bây giờ mà tôi có thể đơn giản hóa ternary bên trong. Nếu tôi ăn cắp ý tưởng của @ tsh thì tôi có thể giảm xuống còn 76 byte:

f=a=>a.reduce((s,e)=>s+=t=1/e?1/t?' '+e:e:`(${f(e)})`,`(${t=a.map(_=>``)})`)

Your program should take either a tuple or a string representing a sugary tupleTôi đoán rằng một mảng các mảng / số nguyên sẽ ổn.
JungHwan Min

1
Chắc chắn điều đó được cho phép
Wheat Wizard

1

R, 316 byte?

(Phải ra ngoài và không chắc chắn cách thích hợp để đếm byte ... cộng với đó không phải là một giải pháp tuyệt vời nhưng muốn đăng nó vì tôi đã dành thời gian để thực hiện nó ...)

p=function(x){
x=eval(parse(text=gsub("\\(","list(",x)))
f=function(j,r=T){
p=paste
s=if(r){"("}else{"(("}
o=paste0(s,p(rep(",",length(j)-1),collapse=""),")")
n=lengths(j)
for(i in seq_along(n)){
v=j[[i]]
if(n[i]>1){v=f(v,F)}
o=p(o,v)}
if(!r){o=p(o,")")}
o=gsub(" *([()]) *","\\1",o)
return(o)}
f(x)
}

Các trường hợp thử nghiệm:

> p("(1,2)")
[1] "(,)1 2"
> p("(1,2,3)")
[1] "(,,)1 2 3"
> p("((1,2),3)")
[1] "(,)((,)1 2)3"
> p("(1,2,3,4)")
[1] "(,,,)1 2 3 4"
> p("(1,(2,3))")
[1] "(,)1((,)2 3)"
> p("(10,1)")
[1] "(,)10 1"


2
Chơi gôn tới 261 byte . Tôi sẽ để lại một lời giải thích cho những gì tôi đã thay đổi, nhưng trớ trêu thay, tôi cũng phải đi ... Nhưng +1, tôi không thể nào không nghĩ tới điều này; công việc tốt đẹp!
Giuseppe

0

JavaScript (ES6), 72 byte

f=(a,b="",c="")=>a.map?b+"("+a.map(x=>'')+")"+a.map(x=>f(x,"(",")"))+c:a

Đầu vào: Mảng chứa số và / hoặc mảng

Đầu ra: chuỗi

Cách sử dụng: f ([...])

Hoàn thành tất cả các trường hợp thử nghiệm, cải tiến chào mừng


0

C, 308 hoặc 339 byte

#include <ctype.h>
#define p putchar
f(s,e,c,i,l)char*s,*e,*c;{i=1,l=40;if(*s++==l){p(l);for(c=s;i;i+=*c==l,i-=*c==41,i+*c==45&&p(44),c++);p(41);}for(;s<e;s=c){for(i=0;isdigit(*s);s+=*s==44)for(i&&p(32),i=1;isdigit(*s);s++)p(*s);*s==l&&p(l);for(c=s,i=1;++c,c<=e&&i;i+=*c==l)i-=*c==41;f(s,c-1);*s==l&&p(41);}}
#define g(x) f(x, x+strlen(x))

308 hoặc 339 byte, tùy thuộc vào việc có truyền con trỏ đến cuối chuỗi đầu vào hay không; dòng cuối cùng chỉ ở đó để cho phép truyền trực tiếp một chuỗi ký tự mà không phải tính toán độ dài của nó.

Giải trình

Một thuật toán khá đơn giản. Nó đếm số dấu phẩy ở độ sâu hiện tại, in chúng dưới dạng hàm dựng, sau đó tiếp tục với các đối số của tuple, thoát (khoảng cách giữa các số, các tuple lồng nhau giữa dấu ngoặc đơn), theo cách đệ quy.

#include <stdio.h>
#include <ctype.h>
typedef enum { false, true } bool;

void tup2ptsfree(char *s, char *e)
{
  int depth;
  char *c;

  if (*s++ == '(') { /* If we are at the start of a tuple, write tuple function `(,,,)` (Otherwise, we are at a closing bracket or a comma) */
    putchar('(');
    /* do the search for comma's */
    c=s; /* probe without moving the original pointer */
    for (depth=1; depth != 0; c++) {
      if (*c == '(') depth++;
      if (*c == ')') depth--;
      if (*c == ',' && depth == 1) putchar(','); /* We have found a comma at the right depth, print it */
    }
    putchar(')');
  }
  while (s < e) { /* The last character is always ')', we can ignore it and save a character. */
    bool wroteNumber;
    for (wroteNumber=false; isdigit(*s); wroteNumber = true) {
      if (wroteNumber) p(' ');           /* If this is not the first number we are writing, add a space */
      while (isdigit(*s)) putchar(*s++); /* Prints the entire number */
      if (*s == ',') s++;                /* We found a ',' instead of a ')', so there might be more numbers following */
    }
    /* Add escaping parenthesis if we are expanding a tuple (Using a small if statement instead of a large branch to prevent doing the same thing twice, since the rest of the code is essentially the same for both cases). */
    if (*s == '(') putchar('(');
    /* Find a matching ')'... */
    c=s+1;
    for (depth=1; c <= e && depth != 0; c++) {
      if (*c == '(') depth++;
      if (*c == ')') depth--;
    }
    /* Found one */
    /* Note how we are looking for a matching paren twice, with slightly different parameters. */
    /* I couldn't find a way to golf this duplication away, though it might be possible. */
    /* Expand the rest of the tuple */
    tup2ptsfree(s, c-1);
    /* idem */
    if (*s == '(') putchar(')');
    /* Make the end of the last expansion the new start pointer. */
    s=c;
  }
}

#define h(x) tup2ptsfree(x, x+strlen(x))

Các trường hợp thử nghiệm và ứng dụng

#include <stdio.h>

#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(*arr))
static char *examples[] = {
  "(1,2)",
  "(10,1)",
  "(1,2,3)",
  "(1,2,3,4)",
  "((1,2),3)",
  "(1,(2,3))",
  "(1,(2,3),4)",
  "((1,2),(3,4))",
  "((1,(2,3)),4,(5,6))",
  "((1,((2,3), 4)),5,(6,7))",
  "(42,48)",
  "(1,2,3,4,5,6,7)"
};

int main(void)
{
  int i;
  for (i=0; i < ARRAYSIZE(examples); i++) {
    printf("%-32s | \"", examples[i]);
    g(examples[i]); /* Test with golfed version */
    printf("\"\n");
    printf("%-32s | \"", examples[i]);
    h(examples[i]); /* Test with original version */
    printf("\"\n");
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.