Trier les manuels

31

Trier les manuels

L'école commence bientôt (si ce n'est pas déjà fait) et il est donc temps de mettre de l'ordre dans nos manuels. Vous devez trier vos livres par ordre alphabétique mais cela prend trop de temps, vous décidez donc d'écrire un programme pour le faire.

Exemples

Contribution:

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

Sortie:

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

Contribution

L'entrée sera un ensemble de livres qui doivent être réorganisés par ordre alphabétique. Il contiendra seulement: |, _, et A-Za-z. Les titres des livres sont lus verticalement, de haut en bas.

Vous pouvez choisir de supposer que l'entrée est remplie d'espaces pour s'adapter à un rectangle. Si vous choisissez de compléter votre entrée avec des espaces, veuillez le préciser dans votre réponse.

La hauteur de livre très maximale que votre programme devra gérer est de 5 120 lignes sans échouer.

Les livres seront toujours d'une épaisseur et leur sera toujours au moins un livre en entrée

Sortie

La sortie devra être le même ensemble de livres organisés par ordre alphabétique. La hauteur des livres doit rester la même et le titre doit avoir le même espacement du haut lorsqu'il est réorganisé.

Les livres doivent être classés par ordre alphabétique. Si votre langue possède une fonction de tri, vous pouvez l'utiliser. Sinon, vous pouvez utiliser le tri alphabétique comme décrit ici .

Exemples de titres de livres

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

Le titre de ce livre est:

"Foo  Bar"

Les titres des livres ne contiendront que des lettres et des espaces.

Les espaces de fin sont autorisés


Gagnant

C'est le donc le code le plus court en octets gagne.

Downgoat
la source
Y a-t-il une limite à la "hauteur" des livres?
The_Basset_Hound
@BassetHound Non, il n'y en a pas actuellement mais ne vous inquiétez pas de prendre en charge les livres de 2 ^ 64-1 de haut. Je mettrai un maximum à 5 120 "de hauteur", c'est ce que votre programme doit gérer sans échec
Downgoat
Très bien.
The_Basset_Hound
@ETHproductions Oui, les titres de livres ne contiendront que des lettres et des espaces
Downgoat
1
Et l'épaisseur des livres? Toujours 1 colonne?
coredump

Réponses:

5

CJam, 60 octets

qN/:Kz1>2%{_{" _"-}#>}$_{_'_#>,}%2,\*2ew{:e>('|*K,Se[}%.\zN*

J'ai essayé de porter ma réponse Python, qui est également similaire à l'approche de @ RetoKoradi .

Essayez-le en ligne . L'entrée doit être complétée par des espaces pour former un rectangle.

Sp3000
la source
7

Python 3, 231 octets

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="")

Juste un petit hack. Zip les livres, trier, rezip, en prenant soin des colonnes |pendant que nous y sommes.

Saisissez une chaîne multiligne, remplie d'espaces de fin dans un rectangle. La sortie a un espace de fin de plus sur chaque ligne que nécessaire.

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
la source
J'aimerais voir une version non golfée, si c'est possible, s'il vous plaît.
Pureferret
1
@Pureferret Ajout d'une version non golfée avec quelques commentaires
Sp3000
6

Ruby (209 204 200 198 octets)

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$/

La transposefonction de cette solution nécessite que toutes les lignes soient de la même longueur, d'où la nécessité de compléter l'entrée avec des espaces.

Explication

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
la source
Quelle rubyversion est requise? Avec 2.1.2 pour l'échantillon d'entrée de la question, j'obtiens «transpose»: la taille de l'élément diffère (6 devrait être 2) (IndexError) ».
manatwork du
@manatwork désolé, j'aurais dû spécifier que la fonction nécessite un rectangle complété par des espaces. Je mettrai à jour la réponse.
Daniel Fone
1
Oh. Effectivement. Désolé, pas analysé de manière exhaustive. Ni aujourd'hui, donc je ne mentionne que gsub(?|,' ')tr(?|,' ').
manatwork
5

Python 2 - 399 octets

S'attend à ce que l'entrée n'ait pas de retour à la ligne de fin.

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
la source
5

CJam, 75 66 65 octets

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

Cela attend une entrée remplie d'espaces pour former un rectangle.

Essayez-le en ligne

Merci à @ Sp3000 et @Dennis pour les suggestions sur la coupe des chaînes sur le chat, ainsi que pour m'avoir indiqué que le $ opérateur peut prendre un bloc comme argument.

Je ne suis toujours pas entièrement satisfait de la deuxième boucle. Mais après avoir essayé quelques autres options sans plus de succès, je me fatigue.

Explication:

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
la source
1

Scala 359 341 octets

s'attend à ce que toutes les lignes soient de la même longueur (c.-à-d. remplies d'espaces)

(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")}

non golfé et commenté:

//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
}
Gil Hoch
la source