라인 정렬!


31

라인 정렬!

문자와 여러 줄 문자열이 주어지면 주어진 구분 기호 사이에 줄의 각 줄을 채우십시오.

입력:

,
Programming, Puzzles
And, Code golf

산출:

Programming, Puzzles
        And, Code golf

입력

입력은 여러 줄 문자열과 문자 (당신이 정렬 할 문자)가되며 원하는 순서 / 형식으로 가져올 수 있습니다. 캐릭터는 한 줄에 정확히 한 번 나타납니다. 입력의 각 라인은 길이가 다를 수 있습니다.

함수 인수 또는 STDIN을 통해 입력 할 수 있습니다.

산출

출력은 동일한 문자열 중앙에 있어야합니다. 후행 줄 바꿈과 후행 공백은 허용되지 않습니다.

출력은 최소 공간 으로 채워 져야 합니다. 입력에서 선행 공백을 제거 할 수 없습니다 (있는 경우).

함수 리턴 또는 STDOUT에서 출력 될 수 있습니다.


전체 프로그램에 대한 입력이 명령 행 인수에서 나올 수 있습니까, 아니면 금지되어 있습니까?
DLosc

@DLosc 예, 물론
Downgoat

1. 함수 / 명령 줄 인수의 경우 단일 문자열을 읽거나 인수 당 한 줄을 허용해야합니까? 2. 최소한 의 공간으로 선 을 채워야합니까?
Dennis

@Dennis You may take it in a single string. Or one-line per argument. "you may take these in any order you wish". Yes, you do need to pad the lines with the minimum amount of spaces. I'll edit the spec
Downgoat

@vihan Can functions take in one line per argument?
xnor

답변:



13

APL (37)

APL just isn't very good at string processing (or I'm not good at golfing, of course).

{⌽∊R,¨' '/⍨¨(⌈/-+)⍺⍳⍨¨⌽¨R←S⊂⍨S=⊃S←⌽⍵}

This takes the character as its left argument, and the multiline string as its right argument. It is assumed that the multiline string ends in a linefeed (e.g. A\nB\nC\n rather than A\nB\nC.) Since I can use "any format [I] wish", and this is also the conventional format for text files, I think this is reasonable.

Explanation:

  • S←⌽⍵: reverse the string, and store it in S.
  • R←S⊂⍨S=⊃S: split S on its first character, and store the array of strings in R.
  • ⍺⍳¨⌽¨R: reverse each string in R, and then find the index of ⍺ (the character) in each string.
  • (⌈/-+): subtract each of the indices from the largest index, giving the amount of spaces needed
  • ' '/⍨¨: for each of those values, generate that many spaces
  • R,¨: add the spaces to each string in R.
  • : join all the strings together
  • : reverse it (to get the original order back)

Example:

      NL←⎕UCS 10 ⍝ newline
      test←'Programming, Puzzles',NL,'And, Code golf',NL
      test ⍝ test string
Programming, Puzzles                
And, Code golf                      

      ⍝ run the function
      +X←','{⌽∊R,¨' '/⍨¨(⌈/-+)⍺⍳⍨¨⌽¨R←S⊂⍨S=⊃S←⌽⍵}test
Programming, Puzzles                        
        And, Code golf                      

      ⍴X ⍝ result is really a string with newlines, not a matrix
44

9

CJam, 23 22 20 bytes

Thanks to Dennis for saving 2 bytes.

ea_rf#_:e>\fm.{S*\N}

This reads the lines from command-line arguments and the character from STDIN.

The online interpreter doesn't support command-line arguments, but you can test an equivalent version here.

Explanation

ea    e# Get the lines from ARGV.
_rf#  e# Duplicate input, read the character and find index of character in each line.
_:e>  e# Duplicate indices and find maximum.
\fm   e# Subtract each index from the maximum index.
.{    e# Apply this block to each pair of line and (max_index - index).
  S*  e#   Get a string with the right amount of spaces.
  \N  e#   Swap spaces with line and push a line feed.
}

9

Pip, 22 20 18 + 1 = 19 bytes

Y_@?qMgsX(MXy)-y.g

Takes strings as command-line arguments and delimiter from STDIN (idea borrowed from Martin's CJam answer). Uses -n flag to print output values on separate lines.

                    g is list of cmdline args; s is space (implicit)
    q               Read the delimiter from stdin
 _@?                Construct a lambda function that takes a string and returns
                       the index of the delimiter in it
     Mg             Map that function to each remaining item in g
Y                   Yank the resulting list of indices into the variable y

         (MXy)-y    Take the max of y minus each element in y
       sX           Space, repeated that many times...
                .g  ... concatenated to each item in g
                    Print, newline-separated (implicit, -n flag)

And an example run:

C:\Users\dlosc> pip.py -ne Y_@?qMgsX(MXy)-y.g "Programming, Puzzles" "And, Code golf"
,
Programming, Puzzles
        And, Code golf

7

JavaScript ES 2015, 113 bytes

f=(c,s)=>s.split`
`.map((e,_,a)=>' '.repeat(a.map(j=>j.indexOf(c)).reduce((g,h)=>g>h?g:h)-e.indexOf(c))+e).join`
`

Not quite as short as the golfing languages posted so far. Takes input as two function arguments, e.g. f(',','Programming, Puzzles\nAnd, Code golf'). The snippet below is ungolfed and includes an easy method to test.

f=function(c,s){
  return s
    .split('\n')
    .map(function(e,_,a){
      return ' '.repeat(
        a.map(function(f){
          return f.indexOf(c)
        }).reduce(function(g,h){
          return g>h?g:h
        })-e.indexOf(c)
      )+e
    })
    .join('\n')
}

run=function(){document.getElementById('output').innerHTML=f(document.getElementById('char').value,document.getElementById('string').value)};document.getElementById('run').onclick=run;run()
<label>Character: <input type="text" id="char" value="," maxlength="1" /></label>
<textarea id="string" rows="4" cols="30" style="display:block">
Programming, Puzzles
And, Code Golf</textarea><button id="run">Run</button><br />
<pre id="output"></pre>



5

Julia, 117 bytes

f(c,t)=(s=[split(l,c)for l=split(t,"\n")];join(map(i->lpad(i[1],maximum(map(i->length(i[1]),s))," ")*c*i[2],s),"\n"))

Ungolfed:

function f(c::String, t::String)
    # Create an array of arrays by splitting on newlines and
    # then on the given delimiter
    s = [split(l, c) for l in split(t, "\n")]

    # Find the maximum length on the left side of the delimiter
    m = maximum(map(i -> length(i[1]), s))

    # Rejoin on the delimiter and pad each line with spaces,
    # and rejoin this with newlines
    join(map(i -> lpad(i[1], m, " ") * d * i[2], s), "\n")
end

5

Python 3, 85 (IDLE 3.2.2, Windows)

c,*s=input().split('\n')
for x in s:print(' '*(max(z.find(c)for z in s)-x.find(c))+x)

Pretty straightforward. This finds the position of the character in the string twice: once to find the max (well, once per line), and once to find the offset. I tried combining these but it was longer.

Python 3 is used for the input unpacking. MY IDLE seems to take multiline strings as input.


@DLosc Works for me in IDLE pasting in a multiline string.
xnor

Hmm. When I do that (IDLE 3.3.4, Windows 7), c gets the delimiter and s gets an empty list. Subsequent calls to input() return the remaining lines one by one.
DLosc

@DLosc Strange. I'm copy-pasting the string directly from my browser into the Idle prompt. Are you doing the same? IDLE 3.2.2, Windows 7 in case it matters.
xnor

Same. Here's a screenshot...
DLosc

@DLosc Still works for me (screenshot). Though I don't understand what's going on, I'm going to say this is compiler or environment specific behavior, and I edited to try to specify the relevant info. The function version is 3 chars longer in Python 2.
xnor

3

Jelly, 12 bytes

Ỵ©w€µạṀ⁶ẋż®Y

Try it online!

Done and golfed with caird coinheringaahing in Jelly Hyper Training (JHT), our Jelly practice chat room.

How it works

The third command line argument (first input) should be the multi-line string, and the character should be the fourth command line argument (second input).

Ỵ©w€µạṀ⁶ẋż®Y  ~ Full program.

Ỵ             ~ Split the string by newlines.
 ©            ~ Copy the result to the register.
  w€          ~ Get the index of the first occurrence of the character on each line.
      Ṁ       ~ Take the maximum.
    µạ        ~ And subtract it from each index, taking the absolute value.
       ⁶ẋ     ~ Repeat a space that many times (vectorizes).
         ż®   ~ Interleave with what was stored in the register.
           Y  ~ Join by newlines and print implicitly.

I am not sure whether taking input as a list of lines is allowed, so this takes a multiline string as input. If it were allowed:

10 bytes

w€µạṀ⁶ẋż³Y

Try it online!


1
that's when you know you have created a successful room
Erik the Outgolfer

2

Matlab / Octave, 106 bytes

Function that uses three separate arguments for character, string, string; and gives result in stdout:

function f(c,s,t)
p=find(s==c)-find(t==c);disp([repmat(32,1,max(-p,0)) s]),disp([repmat(32,1,max(p,0)) t])

Example in Matlab:

>> f(',', 'Programming, Puzzles', 'And, Code golf')
Programming, Puzzles
        And, Code golf

Or try it online with Octave interpreter.


2

Julia, 80 bytes

f(c,s)=(t=split(s,'
');u=[search(i,c)for i=t];join([" "].^(maxabs(u)-u).*t,'
'))

Ungolfed:

function f(c,s)
  # converts multiline string to array of single-line strings
  t=split(s,'\n')

  # creates array of positions of delimiter
  u=[search(i,c)for i=t]

  # Appends appropriate number of spaces to each line
  # (uses elementwise operations to achieve this result)
  v=[" "].^(maxabs(u)-u).*t

  # Recombines array of strings to multiline string and returns
  return join(v,'\n')
end

2

JavaScript (ES6), 105

Using template strings, the 2 newlines are significant and counted.

Test running the snippet in any EcmaScript 6 compatible browser (that is FireFox. Chrome does not support default parameters)

f=(s,c,p=(s=s.split`
`).map(r=>m<(v=r.indexOf(c))?m=v:v,m=0))=>s.map((r,i)=>' '.repeat(m-p[i])+r).join`
`

// Ungolfed
f=(s,c)=>{
  s=s.split('\n')
  p=s.map(r=>r.indexOf(c))
  m=Math.max(...p)
  s=s.map((r,i)=>' '.repeat(m-p[i])+r)
  return s.join('\n')
}  

// TEST
out=x=>O.innerHTML+=x+'\n'

out(f(`Programming, Puzzles
And, Code golf`,','))
<pre id=O></pre>


2

Python 2, 93 bytes

def f(x,y,z):
 p=y.index(x)-z.index(x)
 if p<0:y=" "*abs(p)+y
 else:z=" "*p+z
 print y+'\n'+z

Called like so:

f(',','Programming, Puzzles','And, Code Golf')

2

C# 4.0, 329 320 307 bytes

using System;class P{static void Main(){Func<char,dynamic>f=(d)=>Console.ReadLine().Split(d);var c=f(' ')[0][0];var m=0;var l=new string[9999][];var z=0;for (l[z]=f(c);l[z].Length==2;l[z]=f(c)){m=Math.Max(l[z][0].Length,m);z++;}for(var i=0;i<z;i++){Console.WriteLine("{0,"+m+"}"+c+"{1}",l[i][0],l[i][1]);}}}

Ungolfed version :

using System;
class P
{
    static void Main()
    {
        // lamba to to read a line and split on a char, returns an array of 
        Func<char,dynamic>f=(d)=>Console.ReadLine().Split(d); 
        // read the separator char by taking the first char of the first string 
        // in the array
        // use our lambda
        var c=f(' ')[0][0];
        var m=0; // max position where char is found
        var l=new string[9999][]; // hold all input
        var z=0; // count valid entries in l
        // loop until the input doesn't contain an
        // array with 2 elements
        // here we use our lambda agian, twice
        for (l[z]= f(c);l[z].Length==2;l[z] = f(c))
        {
            // calculate max, based on length 
            // of first element from the string array
            m=Math.Max(l[z][0].Length,m);
            z++; // increase valid items
        }
        // loop over all valid items
        for(var i=0;i<z;i++)
        {
        // use composite formatting with the padding option
        // use the max to create a format string, when max =4 
        // and seperator char is , this will give
        // "{0,4},{1}"
            Console.WriteLine("{0,"+ m +"}"+c+"{1}",l[i][0],l[i][1]);
        }
    }
}

It does accept a maximum of 9999 lines ...


2

Dyalog APL, 22 20 16 bytes

-4 thanks to ngn.

APL is actually not so bad at string processing, if allowed to work with arrays. In this challenge, we may chose the most appropriate format, which for APL means a vector of text vectors as left argument, and the delimiter as a scalar right argument. This even handles multiple delimiters per line, and aligns the first one of each line.

⊣,¨⍨' '⍴¨⍨⌈.⍳-⍳¨

⊣,¨⍨ prepend each line with

' '⍴¨⍨ as many spaces as

⌈.⍳ the rightmost index of the character among the lines

- minus

⍳¨ the index of the character in each line

Try APL online! ( added to print output vertically)

Bonus? Works for any number of strings, and delimiters (aligns by left-most).


⊣,¨⍨' '⍴¨⍨⌈.⍳-⍳¨
ngn

Yes, of course.
Adám

1

C#, 191

As a function. Roughly a porting of my JS answer.

using System.Linq;string f(string s,char c){var q=s.Split('\n');int m=0,v;Array.ForEach(q,x=>m=m<(v=x.IndexOf(c))?v:m);return String.Join("\n",q.Select(x=>new String(' ',m-x.IndexOf(c))+x));}

1

Ruby, 74 bytes

l=lambda{|d,s|s.each{|e|puts ' '*(s.map{|f|f.index(d)}.max-e.index(d))+e}}

and call it like

l.call ',',['Programming, Puzzles','And, Code golf']

1

R, 68 bytes

function(c,x,y,r=regexpr)cat(x,"\n",rep(" ",r(c,x)-r(c,y)),y,sep="")

Unnamed function that takes 3 inputs; c which is the character to align, x is the first string and y the second string.

In R, the function regexpr returns the position of a given pattern in a string. The solution works by applying regexpr on both strings and repeating white spaces amounting to the difference and subsequently just print both inputs separated by a newline.


0

Python 2, 67 66 bytes

def a(d,l):
 i=l[0].index(d)
 for e in l:print' '*(i-e.index(d))+e

Called with:

a(',', ['Programming, Puzzles', 'And, Code golf'])

0

Moonscript, 138 bytes

(n)=>
 i=0
 @='
'..@
 l=[b-a for a,b in @gmatch "
().-()"..n]
 m=math.max unpack l
 (@gsub '
',(a)->
  i=i+1
  a..(' ')\rep m-l[i])\sub(2)

This returns a function which takes 2 arguments. The first is the string, the second is the character to align on. These arguments are the implicit argument @, and n.

First, I append a new line to the string, to make processing easier.

@='
'..@

Now, I generate a list of the positions of every alignment character, using gmatch. Next, I replace the newline before every line with the correct number of spaces, then trim the newline I added at the beginning.


0

Lua, 169 bytes

function a(d,t)m={}for k,v in pairs(t)do m[#m+1]=string.find(v,d)end o=math.max(unpack(m))for k,v in pairs(t)do print(string.rep(" ",o-(string.find(v,d)or 0))..v)end end

Not as short as other answers but this is my first one :D


0

Retina, 71 bytes

+`^((.)(.*¶)*)((.)*\2.*¶)((?<-5>.)*(?(5)\2|(.)\2).*)
$1$#7$* $4$#5$* $6

Try it online! Note: This leaves the alignment character in the output; it can be deleted at a cost of 4 bytes. If only two strings need to be aligned, then for 52 bytes:

^(.)¶((.)*\1.*¶)((?<-3>.)*(.)*\1.*)
$#5$* $2$#3$* $4

Explanation:

^(.)¶

This matches the alignment character.

((.)*\1.*¶)

This matches the first line and also keeps track of how many characters there were before the alignment character. (.NET keeps a match stack for each variable, in this case, $3.)

((?<-3>.)*(.)*\1.*)

This matches the second line, trying to account for as many characters as we found on the first line. ?<-3> causes the match to pop the stack for each character, until it is empty, at which point the match fails, and the (.)* then matches the remaining characters before the alignment character. At this point we have the following variables:

  • $1 contains the alignment character
  • $2 contains the first line
  • $3 contains a stack whose length is the first line prefix minus the second line prefix
  • $4 contains the second line
  • $5 contains a stack whose length is the second line prefix minus the first line prefix

$#5$* then prefixes the necessary number of spaces to make the first line align with the second, and vice versa for $#3$*.

Similar logic applies to the main answer, except here we have to find two lines which don't align so that we can align them (this is where the ?(5) comes in) and then repeat the alignment over all the lines until they are all equally aligned.


0

Common Lisp, 101 bytes

(lambda(c l)(dolist(x l)(format t"~,,v@a~%"(-(apply'max(mapcar(lambda(x)#1=(position c x))l))#1#)x)))

The first parameter is the character, the second is a list of string to be aligned.

Try it online!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.