Stampa lista di larghezza fissa ordinata per colonna

4

Ho un elenco di lunghezza variabile in cui gli elementi sono stringhe di lunghezza variabile. Voglio stamparli con (N speculare) / ordinare per colonna.

I punti principali sono:

  • Le colonne devono avere una larghezza fissa == i dati più ampi in quella colonna.
  • Deve essere il più compatto possibile.
  • Il numero di colonne è variabile / indotto dalla larghezza della tela disponibile.
  • L'ordine degli articoli dovrebbe non essere riorganizzato.
  • (Gli elenchi di articoli stampati su colonna in ordine orizzontale mi disgustano.)

A scelta:

  • La distribuzione dovrebbe facoltativamente preferire in basso a sinistra o in alto a destra.

Attualmente lo uso in terminale da bash, C ecc. ma altri usi non sono difficili da immaginare.

Il risultato dei calcoli dovrebbe essere:

  • Colonne
  • linee
  • larghezza di ogni colonna

Come, da questo, si può facilmente stampare i dati in una tabella fissa con colonne.

Domanda principale : esiste un modo elegante per farlo. (Mi ispiro alle riflessioni di Knuth's Computer .)

Il mio attuale approccio è piuttosto semplice. Difficile specificare la domanda senza alcuni dettagli cruenti, quindi eccoci qui:

Esempi di dati

es. (tramite l'indice dell'array di stringhe):

0  4  8 12   or    0  4  8 12     or   0  3  6  9 12 15
1  5  9 13         1  5  9 13          1  4  7 10 13
2  6 10 14         2  6 10             2  5  8 11 14
3  7 11 15         3  7 11             

favouring lower left     favouring upper right
0  4  8 12               0  4  8 11
1  5  9 13               1  5  9 12
2  6 10                  2  6 10 13
3  7 11                  3  7

es. (per dati - output effettivo):

0) Item number 00000 4) Item Number 04        8) Item Number 008   12) Item Number 00012
1) Item Number 00001 5) Item Number 5         9) Item Number 00009 13) Item Number 0013 
2) Item Number 02    6) Item Number 00000006 10) Item Number 10   
3) Item Number 003   7) Item Number 7        11) Item Number 11

Implementazione corrente

A partire da ora lo faccio da (circa) ad es. in bash:

  1. Aggiunta della lunghezza di ogni elemento all'array lens e traccia% elemento% ch_de%.
  2. Aggiungi larghezza per il numero + 1 per longest + 1 per ) a space elemento.
  3. Calcola le colonne massime in base alla larghezza.
  4. Ricalcolo della larghezza del numero dell'articolo (quello prima longest nella stampa.) per ogni colonna.
  5. Calcolo della larghezza effettiva più lunga per gli articoli in ogni colonna.
  6. Re-calcolo:

     while 'lines' > 1 ; do
    
          * Available width = Canvas width - total print width
          * Test:
                Find longest item in last column as if columns was increased by 1.
          * If longest_in_last_column_test < available width
                 increase columns by 1.
                 recalculate all column widths.
            Else
                 break
            End If
     done
    
  7. Stampa elenco.

Pensieri

Non posso aiutare, ma mi chiedo se ci sia un modo per calcolarlo con altri mezzi. Per esempio. usando la matematica a matrice, - o forse un buon algoritmo là fuori.

Forse difficile in bash, ma in C da puntatori a struct o linguaggi correlati agli oggetti.

Exempli gratia:

struct item {
    int len;
    char *val;
}

struct item items = {{5, "Hello"}, {3, "You"}, ...}

Quale darebbe una matrice tipicamente

# index:length
0:5 1:2 2:1 3:3 4:5 
5:2 6:6 7:9 8:1 9:6

Quindi avendo il vincolo di somma di ogni riga di < = larghezza disponibile, ad es. 25, riorganizzare la matrice.

longest: 5 5 9 6 => sum 25
--------------------------
         5 3 6 1 => sum 15
         5 5 9 6 => sum 25
         1 2 1   => sum  4
    
posta Runium 11.02.2013 - 20:50
fonte

1 risposta

1

Ecco cosa ho scoperto:

struct Item
{
    uint prefix_length; // for the prefix numbers; e.g. "100) " would be length 5
    uint item_length;   // length of the item
    char *item;         // string contents
}

struct Column
{
    uint starting_index;
    uint num_items;
    uint max_prefix_length;
    uint max_item_length;
}

/*

inizializzazione

Crea una lista di Item s e inizializza la loro prefix_length s in base a dove sono nella lista e w / e altri caratteri che il prefisso avrà (cioè numero di lunghezza + paren + spazio del buffer).

Quindi crea un elenco (dinamico) di Column s, della stessa lunghezza del numero di Item s, con il starting_index di ogni colonna impostata sul suo indice nell'elenco (in modo che corrisponda ad un Item ) e num_items impostato su 1. Il max_prefix_length e max_item_length devono essere inizializzati con i valori corrispondenti del Item a cui sta puntando Column .

Items: [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [...]
         ^     ^     ^     ^     ^     ^     ^     ^
Cols:    0     1     2     3     4     5     6    ...

Main Loop

La prima cosa da fare nel ciclo principale sarebbe iterare attraverso Column s, incrementando num_items di 1 e incrementando starting_index di 0 per il primo Column , di 1 per il secondo% di co_de %, per 2 per il terzo Column , ecc.

Dopo la prima iterazione questo ti darà:

Items: [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [...]
         ^     ^     ^     ^     ^     ^     ^     ^
Cols:    +--0--+     +--1--+     +--2--+     +--3--+  ...

La seconda iterazione otterrebbe:

Items: [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [...]
         ^           ^     ^           ^     ^
Cols:    +-----0-----+     +-----1-----+     +-----2-...

Tieni presente che dovrai rimuovere qualsiasi Column s il cui Column diventa maggiore del numero di elementi nell'elenco starting_index s.

Dopo aver incrementato questi valori, imposta Item di ogni max_prefix_length sul valore corrispondente dell'ultimo Column a cui punta. Per Item , purtroppo, dovrai scorrere il max_item_length s il Item spans per trovare il max Column .

La condizione di terminazione del ciclo principale sarà di vedere se la somma del item_length + max_prefix_length di tutte le colonne (più lo spazio del buffer tra le colonne che vuoi) è inferiore alla larghezza totale che hai. (Non dimenticare la condizione limite di un max_item_length che ha una lunghezza maggiore della larghezza totale.) EDIT: Purtroppo questa condizione di terminazione richiederebbe di mantenere il risultato dell'ultima iterazione in giro, poiché il ciclo terminerebbe solo dopo è stato trovato un risultato non valido.

Se ci fosse un modo per fare un massimo di camminata per gli oggetti misurati da ogni colonna, sarebbe fantastico (ma purtroppo non riesco a pensarne uno al momento).

Naturalmente, dopo aver scritto tutto questo, vedo che fondamentalmente sta arrivando da questa direzione opposta al tuo algoritmo; forse ti darà alcune idee però.

    
risposta data 12.02.2013 - 19:29
fonte

Leggi altre domande sui tag