Sortieren Sie die Lehrbücher

31

Sortieren Sie die Lehrbücher

Die Schule beginnt bald (falls noch nicht geschehen) und es ist Zeit, unsere Lehrbücher in Ordnung zu bringen. Sie müssen Ihre Bücher in alphabetischer Reihenfolge sortieren, aber das dauert zu lange, sodass Sie sich dafür entscheiden, ein Programm zu schreiben.

Beispiele

Eingang:

 _
| |  _
|F| | |
|o|_|P|
|o|B|P|
| |a|C|
| |r|G|
|_|_|_|

Ausgabe:

   _
  | |_
  |F| | 
 _|o|P|
|B|o|P|
|a| |C|
|r| |G|
|_|_|_|

Eingang

Die Eingabe besteht aus einer Reihe von Büchern, die alphabetisch neu angeordnet werden müssen. Es enthält nur: |,_ , , und A-Za-z. Die Titel der Bücher werden vertikal von oben nach unten gelesen.

Sie können annehmen, dass die Eingabe mit Leerzeichen aufgefüllt ist, um sie an ein Rechteck anzupassen. Wenn Sie Ihre Eingabe mit Leerzeichen auffüllen möchten, geben Sie dies in Ihrer Antwort an.

Die maximale Buchhöhe, die Ihr Programm verarbeiten muss, beträgt 5.120 Zeilen.

Die Bücher werden immer 1-dick sein und es wird immer mindestens ein Buch in der Eingabe sein

Ausgabe

Die Ausgabe muss dieselbe Gruppe von Büchern sein, die in alphabetischer Reihenfolge angeordnet sind. Die Höhe der Bücher muss gleich bleiben und der Titel muss bei der Neuanordnung den gleichen Abstand von oben haben.

Bücher sollten alphabetisch sortiert sein. Wenn Ihre Sprache eine Sortierfunktion hat, können Sie diese verwenden. Ansonsten können Sie die hier beschriebene alphabetische Sortierung verwenden .

Buchtitel-Beispiele

 _
| |
| |
|F|
|o|
|o|
| |
| |
|B|
|a|
|r|
| |
| |
|_|

Dieser Buchtitel lautet:

"Foo  Bar"

Buchtitel enthalten nur Buchstaben und Leerzeichen.

Leerzeichen dürfen nachgestellt werden


Gewinnen

Das ist also gewinnt der kürzeste Code in Bytes.

Downgoat
quelle
Gibt es eine Grenze für die "Höhe" der Bücher?
The_Basset_Hound
@BassetHound Nein, es gibt derzeit keine Bücher mit einer Größe von 2 ^ 64-1, aber Sie müssen sich keine Gedanken darüber machen, wie Sie Bücher unterstützen können. Ich werde ein Maximum von 5.120 setzen. "
Groß
Okay, großartig.
The_Basset_Hound
@ETHproductions Ja, Buchtitel enthalten nur Buchstaben und Leerzeichen
Downgoat
1
Was ist mit der Dicke der Bücher? Immer 1 Spalte?
Coredump

Antworten:

7

Python 3, 231 Bytes

def f(s):
 *M,L=sorted(["".join(c).strip()for c in zip(*s.split("\n"))][1::2],key=lambda x:x[1:-1].strip()),;l=m=0
 for r in L+[""]:n=len(r);M+="|"*~-max(n,l),r;m=max(n,m);l=n
 for r in zip(*[x.rjust(m)for x in M]):print(*r,sep="")

Nur ein kurzer Hack. Zippen Sie die Bücher, sortieren, rezip, kümmern Sie sich um die Spalten, |während wir gerade dabei sind.

Geben Sie eine mehrzeilige Zeichenfolge ein, die mit Leerzeichen am Ende eines Rechtecks ​​aufgefüllt ist. Die Ausgabe enthält in jeder Zeile ein Leerzeichen mehr als erforderlich.

Ungolfed

def f(s):
  new_cols = []

  # Zip columns, removing the spaces above each book
  # [1::2] is to skip columns of |s, keeping only the books
  books = ["".join(c).strip() for c in zip(*s.split("\n"))][1::2]

  # Sort based on title, [1:-1] to remove the top and bottom _s
  books.sort(key=lambda x:x[1:-1].strip())

  last = 0
  max_height = 0

  for book in (books + [""]):
    height = len(book)

    # Append |s as necessary for the left edge of the current book
    # The +[""] above is for the right edge of the last book
    new_cols.extend(["|"*(max(height, last) - 1), book])

    max_height = max(height, max_height)
    last = height

  # Rezip columns, add back spaces as necessary and print
  for col in zip(*[x.rjust(max_height) for x in new_cols]):
      print("".join(col))
Sp3000
quelle
Ich würde gerne eine ungolfed Version sehen, wenn es möglich ist, bitte.
Pureferret
1
@ Pureferret Hinzugefügt eine ungolfed Version mit ein paar Kommentaren
Sp3000
6

Rubin (209 204 200 198 Bytes)

a=n.tr(?|,' ').split$/
i=!p;t=a.map(&:chars).transpose.map(&:join).select{i^=a}.sort_by{|s|s[/[A-Z]/][0]}
x=0;t.map{|t|y=0;u=p;t.chars{|c|u&&a[y][x,3]=?|*3;a[y][x+1]=c;y+=1;u|=c=='_'};x+=2}
a.join$/

Die transposeFunktion in dieser Lösung erfordert, dass alle Zeilen die gleiche Länge haben, daher muss die Eingabe mit Leerzeichen aufgefüllt werden.

Erläuterung

def sort_books(n)
  a = n.tr(?|,' ')  # pre-emptively remove all the '|'.
    .split $/         # and split into an array of lines
                      # ($/ is the INPUT_RECORD_SEPARATOR, typically "\n")
                      # we're going to write our answer into `a` later

  i = !p # i = true; we'll use this as a flip-flop variable
         # Kernel#p returns nil with no args

  # we're now going to get a sorted array of book titles (t)
  t = a.map(&:chars)  # break array into nested array of every character
       .transpose     # and transpose the entire array
       .map(&:join)   # this gives us an array of "horizontal" book titles with dividers

       .select { i ^= a } # select every second line
                          # (i.e. just titles without dividers)
                          # `i` starts off true
                          # `a` is truish (it's our original array)
                          # `^=` is the bitwise xor assignment,
                          #      it will alternate true/false on each execution

       .sort_by { |s| s[/[A-Z]/][0] } # sort by the first alphabetical char

  # use counters for less chars than `each_with_index`
  # x and y are cartesian coordinates in the final array

  x = 0 # start in the left-hand column

  # go through each title
  t.map { |t|
    y = 0 # each book title starts on the top row

    u = p # `u` is "have we reached the book's spine yet?" (or are we above it?)
          # `u` starts off false and we'll set it true when we see the first '_'
          # after which we'll start writing the book's edges

    # go through each character of each title, including leading spaces and '_'s
    # this will "descend" down the array writing each letter of the title
    # along with the "edges"
    t.chars { |c|

      u &&                  # if we're on the spine
        a[y][x,3] = ?|*3;   # write ||| in the next 3 columns
                            # the middle | will be overwriten by the title char

      a[y][x+1] = c; # write the current title char into the second (x+1) column

      y+=1; # descend to the next row

      u |= c == '_' # Since '_' is the top and bottom of the book,
                    # this toggles whether we're on the spine
    }
    x += 2 # jump to the right 2 columns and start on the next title
  }
  a.join $/ # hopefully this is obvious
end
Daniel Fone
quelle
Welche rubyVersion wird benötigt? Mit 2.1.2 für die Beispieleingabe aus der Frage erhalte ich "transponieren": Elementgröße unterscheidet sich (6 sollte 2 sein) (IndexError) ".
Manatwork
@manatwork sorry, ich hätte angeben sollen, dass die Funktion ein mit Leerzeichen aufgefülltes Rechteck benötigt. Ich werde die Antwort aktualisieren.
Daniel Fone
1
Oh. Tatsächlich. Entschuldigung, nicht ausführlich analysiert. Weder heute noch, deshalb erwähne ich nur gsub(?|,' ')tr(?|,' ').
Manatwork
5

Python 2 - 399 Bytes

Erwartet, dass die Eingabe keine nachgestellte Zeile enthält.

import sys;a=str.strip;L=list(sys.stdin);b=len(L[-1])/2;s=['']*b
for l in L:
    i=0
    for c in l[1:-1:2]:s[i]+=c;i+=1
s=sorted([a(a(x),'_')for x in s],key=a);y=map(len,s);m=[y[0]]+[max(y[i],y[i+1])for i in range(b-1)]
for i in range(max(y)+1):
    h=max(y)-i;l='';j=0
    for x in s:l+='|'if h<m[j]else' ';l+='_' if h==len(x)else' 'if h>len(x)else x[-h-1];j+=1
    print l+('|'if h<y[-1]else' ')
print'|_'*b+'|'
Tyilo
quelle
5

CJam, 75 66 65 Bytes

qN/z(;2%{_{" _"#W=}#>}$es:P;_W>+{_'_#_Pe<)S*2$,'|*.e<@@:P;}%);zN*

Dies setzt voraus, dass die Eingabe mit Leerzeichen aufgefüllt wird, um ein Rechteck zu bilden.

Probieren Sie es online aus

Vielen Dank an @ Sp3000 und @Dennis für Vorschläge zum Trimmen von Saiten im Chat sowie für den Hinweis, dass der $Operator einen Block als Argument nehmen kann.

Ich bin immer noch nicht ganz zufrieden mit der zweiten Runde. Aber nachdem ich ein paar andere Optionen ohne besseren Erfolg ausprobiert habe, werde ich müde.

Erläuterung:

qN/     Read input and split at newlines.
z       Transpose to turn columns into lines.
(;      Drop first line...
2%      ... and every second line after that, to keep only lines with titles.
{       Start block that maps lines for sort.
  _       Copy.
  {       Start block for matching first title letter.
    " _"#   Search for character in " _".
    W=      True if not found.
  }#      End match block. This gets position of first character not in " _".
  >       Trim leading spaces and '_.
}$      End of sort block. Lines are now sorted alphabetically by title.
es:P;   Store large number in P. P holds previous position of '_ in following loop.
_W>+    Repeat last title line, so that final separator line is generated.
{       Loop over title lines.
  _'_#    Find position of '_.
  _       Copy position. Will store it in P after the minimum has been determined.
  P       Get position of '_ in previous line.
  e<)     Take the smaller of the two '_ positions, and decrement.
  S*      Generate leading spaces from the count.
  2$,     Get length of title line.
  '|*     Generate full line length sequence of '|.
  .e<     Overlap spaces with '| to give the final separator.
  @@      Get '_ position to top, and stack in order for next loop iteration.
  :P;     Store '_ position in P.
}%      End of loop over lines.
);      Remove last line, which was a repeat.
z       Transpose to turn lines into columns again.
N*      Join with newline characters.
Reto Koradi
quelle
1

Scala 359 341 Bytes

erwartet, dass alle Zeilen die gleiche Länge haben (dh mit Leerzeichen aufgefüllt sind)

(s:String)=>{def f(s:String)=(" "/:s)((r,c)=>if(r.last=='|'||c=='_')r+"|"else r+" ").init;val h=s.lines.toSeq.transpose.collect{case s if s.exists(_.isLetter)=>s.mkString}.sortBy(_.filter(!_.isWhitespace));((Seq(f(h(0)))/:h.sliding(2))((s,l)=>s:+l(0):+f(l.minBy(_.indexOf('_')))):+h.last:+f(h.last)).transpose.map(_.mkString).mkString("\n")}

ungolfed & kommentiert:

//anonymous method that takes the books ascii-art string
(s: String) => {

  //method to convert the middle to a border
  def f(s: String) =
    //fold (starting from non empty string since we use `.last`)
    (" "/:s)((r,c) =>
      if(r.last=='|'||c=='_')r+"|"
      else r+" "
    ).init.tail

  //h is a sequence of strings of the middle of the books
  val h =
    //transpose lines of input string, and take only the lines the contains letters (middle of the books)
    s.lines.toSeq.transpose.collect{
      case s if s.exists(_.isLetter) =>
        s.mkString
    }.sortBy(_.filter(!_.isWhitespace)) //sort the books by title (actually by "_$title" since we filter out just whitspaces)

  //fold over pairs of books and add the last manually
  (
    (Seq(f(h(0)))/:h.sliding(2))((s,l) =>
      s :+ l(0) :+ f(l.minBy(_.indexOf('_'))) //convert higher book to border and append to folded accumulator
    ) :+ h.last :+ f(h.last) //add last book manually
  ).transpose.map(_.mkString).mkString("\n") //transpose back and construct the output string
}
Gilad hoch
quelle