Sortir Buku Teks

31

Sortir Buku Teks

Sekolah akan segera dimulai (jika belum) dan inilah saatnya untuk memesan buku pelajaran kami. Anda perlu mengurutkan buku-buku Anda dalam urutan abjad tetapi itu terlalu lama sehingga Anda memutuskan untuk menulis sebuah program untuk melakukannya.

Contohnya

Memasukkan:

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

Keluaran:

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

Memasukkan

Masukan akan berupa serangkaian buku yang perlu disusun ulang sesuai abjad. Ini hanya akan berisi: |, _, , dan A-Za-z. Judul-judul buku dibaca secara vertikal, atas-bawah.

Anda dapat memilih untuk menganggap input diisi dengan spasi putih agar sesuai dengan persegi panjang. Jika Anda memilih untuk memasukkan input Anda dengan spasi, harap tentukan ini dalam jawaban Anda.

Ketinggian buku maksimum yang harus ditangani oleh program Anda adalah setinggi 5.120 baris tanpa gagal.

Buku-buku akan selalu setebal 1 dan mereka akan selalu setidaknya satu buku di input

Keluaran

Outputnya harus berupa kumpulan buku yang sama yang disusun dalam urutan abjad. Ketinggian buku harus tetap sama dan judul harus memiliki jarak yang sama dari atas ketika disusun kembali.

Buku harus disortir berdasarkan abjad. Jika bahasa Anda memiliki fungsi sortir, Anda dapat menggunakannya. Kalau tidak, Anda dapat menggunakan penyortiran alfabet seperti yang dijelaskan di sini .

Contoh Judul Buku

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

Judul buku ini adalah:

"Foo  Bar"

Judul buku hanya akan berisi huruf dan spasi.

Trailing whitespace diizinkan


Kemenangan

Ini adalah sehingga kode terpendek dalam byte menang.

Downgoat
sumber
Apakah ada batasan "tinggi" buku?
The_Basset_Hound
@BassetHound Tidak, saat ini tidak ada tetapi tidak perlu khawatir tentang buku-buku pendukung setinggi 2 ^ 64-1. Saya akan menempatkan maksimum di 5.120 "tinggi" adalah apa yang perlu ditangani oleh program Anda tanpa gagal
Downgoat
Baiklah, bagus.
The_Basset_Hound
@ETHproductions Ya, judul buku hanya akan berisi huruf dan spasi
Downgoat
1
Bagaimana dengan ketebalan buku? Selalu 1 kolom?
coredump

Jawaban:

5

CJam, 60 byte

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

Saya mencoba porting jawaban Python saya, yang juga mirip dengan pendekatan @ RetoKoradi .

Cobalah online . Input harus diisi dengan spasi untuk membentuk persegi panjang.

Sp3000
sumber
7

Python 3, 231 byte

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

Hanya hack cepat. Masukkan buku, sortir, rezip, rawat kolom| saat kita sedang mengerjakannya.

Masukkan string multiline, berlapis dengan spasi tambahan ke persegi panjang. Output memiliki satu ruang trailing lebih pada setiap baris dari yang diperlukan.

Tidak disatukan

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
sumber
Saya akan senang melihat versi yang tidak diserang, jika memungkinkan, silakan.
Pureferret
1
@ Pureferret Menambahkan versi yang tidak diklik dengan beberapa komentar
Sp3000
6

Ruby (209 204 200 198 byte)

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

Itu transpose fungsi dalam solusi ini mensyaratkan bahwa semua garis panjang yang sama, maka input harus empuk dengan spasi.

Penjelasan

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
sumber
rubyVersi mana yang dibutuhkan? Dengan 2.1.2 untuk input sampel dari pertanyaan, saya mendapatkan "` transpos ': ukuran elemen berbeda (6 harus 2) (IndexError) ".
manatwork
@ manatwork maaf, saya seharusnya sudah menentukan bahwa fungsi ini membutuhkan persegi panjang yang diisi oleh spasi. Saya akan memperbarui jawabannya.
Daniel Fone
1
Oh Memang. Maaf, belum dianalisis secara mendalam. Baik hari ini, jadi saya hanya menyebutkan gsub(?|,' ')tr(?|,' ').
manatwork
5

Python 2 - 399 byte

Diharapkan input tidak memiliki baris baru.

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
sumber
5

CJam, 75 66 65 byte

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

Ini mengharapkan input yang diisi dengan spasi untuk membentuk persegi panjang.

Cobalah online

Terima kasih kepada @ Sp3000 dan @Dennis untuk saran tentang pemangkasan string pada obrolan, serta memberi tahu saya bahwa $ operator dapat mengambil blok sebagai argumen.

Saya masih belum sepenuhnya senang dengan loop kedua. Tetapi setelah mencoba beberapa opsi lain tanpa keberhasilan yang lebih baik, saya mulai lelah.

Penjelasan:

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
sumber
1

Scala 359 341 byte

mengharapkan semua garis memiliki panjang yang sama (yaitu berlapis dengan spasi)

(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 & berkomentar:

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