Comprimi una matrice sparsa


18

Comprimi una matrice sparsa usando la riga sparsa compressa (formato CSR, CRS o Yale) .

Questi sono tutti la stessa forma di compressione (ignora il nuovo Yale).

L'input può essere qualsiasi struttura di dati 2d (elenco di elenchi, ecc.): Ad es

[[0 0 0 0],
 [5 8 0 0],
 [0 0 3 0],
 [0 6 0 0]]

E l'uscita dovrebbe essere tre strutture dati 1d (elenco etc), che indicano le uscite A, IAe JA, per esempio

[5, 8, 3, 6]
[0, 0, 2, 3, 4]
[0, 1, 2, 1,]

Il processo è descritto da Wikipedia:

  • La matrice A è di lunghezza NNZ e contiene tutte le voci diverse da M in ordine da sinistra a destra dall'alto verso il basso ("riga maggiore").

  • L'array IA è di lunghezza m + 1. È definito da questa definizione ricorsiva:

    • IA [0] = 0 IA [i] = IA [i - 1] + (numero di elementi diversi da zero sulla riga (i - 1) nella matrice originale)

    • Pertanto, i primi m elementi di IA memorizzano l'indice in A del primo elemento diverso da zero in ciascuna riga di M e l'ultimo elemento IA [m] memorizza NNZ, il numero di elementi in A, che può anche essere considerato come il indice in A del primo elemento di una riga fantasma appena oltre la fine della matrice M. I valori dell'i-esima riga della matrice originale vengono letti dagli elementi da A [IA [i]] a A [IA [i + 1] - 1] (inclusivo su entrambe le estremità), ovvero dall'inizio di una riga all'ultimo indice appena prima dell'inizio del successivo. [5]

    • Il terzo array, JA, contiene l'indice di colonna in M ​​di ciascun elemento di A e quindi è anch'esso di lunghezza NNZ.

Se la tua lingua non supporta le strutture dati effettive, l'input e l'output potrebbero essere di testo.

Casi test

Ingresso 1:

[[0 0 0 0],
 [5 8 0 0],
 [0 0 3 0],
 [0 6 0 0]]

Uscita 1:

[ 5, 8, 3, 6 ]
[ 0, 0, 2, 3, 4 ]
[ 0, 1, 2, 1, ]

Ingresso 2

[[10 20 0 0 0 0],
 [0 30 0 40 0 0],
 [0 0 50 60 70 0],
 [0 0 0 0 0 80]]

Uscita 2:

[ 10 20 30 40 50 60 70 80 ]
[  0  2  4  7  8 ]
[  0  1  1  3  2  3  4  5 ]

Ingresso 3:

[[0 0 0],
 [0 0 0],
 [0 0 0]]

Uscita 3:

[ ]
[ 0 0 0 0 ]
[ ]

Ingresso 4:

[[1 1 1],
 [1 1 1],
 [1 1 1]]

Uscita 4:

[ 1 1 1 1 1 1 1 1 1 ]
[ 0 3 6 9 ]
[ 0 1 2 0 1 2 0 1 2 ]

Ingresso 5:

[[0 0 0 0],
 [5 -9 0 0],
 [0 0 0.3 0],
 [0 -400 0 0]]

Uscita 5:

[ 5, -9, 0.3, -400 ]
[ 0, 0, 2, 3, 4 ]
[ 0, 1, 2, 1, ]

Supponiamo che gli input possano contenere qualsiasi numero reale, non è necessario prendere in considerazione simboli matematici o rappresentazione esponenziale (ad es. 5.000 non verranno mai inseriti come 5e3). Non avrete bisogno di gestire inf, -inf, NaNo di qualsiasi altro 'pseudo-numeri'. È possibile produrre una diversa rappresentazione del numero (5.000 possono essere emessi come 5e3, se lo si desidera).

punteggio:

Questo è un , vince meno byte.

Classifiche

Ecco uno snippet di stack per generare sia una classifica regolare che una panoramica dei vincitori per lingua.

Per assicurarti che la tua risposta venga visualizzata, ti preghiamo di iniziare la risposta con un titolo, utilizzando il seguente modello Markdown:

# Language Name, N bytes

dov'è Nla dimensione del tuo invio. Se si migliora il punteggio, è possibile mantenere i vecchi punteggi nel titolo, colpendoli. Per esempio:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Se si desidera includere più numeri nell'intestazione (ad es. Perché il punteggio è la somma di due file o si desidera elencare separatamente le penalità del flag dell'interprete), assicurarsi che il punteggio effettivo sia l' ultimo numero nell'intestazione:

# Perl, 43 + 2 (-p flag) = 45 bytes

Puoi anche rendere il nome della lingua un collegamento che verrà quindi visualizzato nello snippet della classifica:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes


Potrebbero essere utilizzati indici basati su 1 per l'ultima riga?
Leo,

@Leo per JA? No.
Pureferret,

1
Non è del IA[0] = 0tutto inutile? È necessario solo definire IA[i] = IA[i − 1]..., ma potremmo semplicemente affermare che se i-1 < 0usare 0. Cioè, IA [0] è sempre uguale a 0, quindi può essere compresso (sì, mi rendo conto che questa è una critica dell'algoritmo, non questa sfida).
Draco18s

Avremo anche la sfida inversa?
Adám,

1
! Neat Non si era mai imbattuto in nessuno dei due formati prima, ma sono contento di aver visto prima qualcun altro (non dovrei essere il tipo di persona che individua banali ottimizzazioni negli algoritmi così vecchi).
Draco18s,

Risposte:


6

MATL , 19 byte

!3#f!Dx0Gg!XsYshDq!

L'input utilizza ;come separatore di righe.

Provalo online! Oppure verifica tutti i casi di test: 1 , 2 , 3 , 4 , 5 .

Spiegazione

!     % Implicit input. Transpose
3#f   % 3-output version of find: it takes all nonzero values and pushes
      % their column indices, row indices, and values, as column vectors
!     % Transpose into a row vector
D     % Display (and pop) vector of values
x     % Delete vector of row values
0     % Push 0
G     % Push input
g     % Convert to logical: nonzeros become 1
!     % Transpose
Xs    % Sum of columns. Gives a row vector
Ys    % Cumulative sum
h     % Prepend the 0 that's below on the stack
D     % Display (and pop) that vector
q     % Subtract 1 from the vector of row indices
!     % Transpose into a row vector. Implicitly display


3

Haskell, 87 byte

f s|a<-filter(/=0)<$>s=(id=<<a,scanl(+)0$length<$>a,s>>= \t->[i|(i,e)<-zip[0..]t,e/=0])

Provalo online!

Come funziona:

a<-filter(/=0)<$>s           -- let a be the list of lists with all 0 removed]
                             -- e.g. [[1,0,0],[0,3,4]] -> [[1],[3,4]]

                             -- return a triple of

id=<<a                       -- a concatenated into a single list -> A 

scanl(+)0$length<$>a         -- partial sums of the length of the sublists of a
                             -- strating with an additional 0 -> IA

s>>=                         -- map the lambda over the sublists of s and concatenate
                             -- into a single list
   \t->[i|(i,e)<-zip[0..]t,e/=0]  -- the indices of the non-zero elements -> JA


2

APL (Dyalog) , 31 28 caratteri o 36 33 byte *

Richiede l' ⎕IO←0indicizzazione in base zero. L'I / O è un elenco di elenchi.

{(∊d)(0,+\≢¨d←⍵~¨0)(∊⍸¨⍵≠0)}

Provalo online!

{... } funzione anonima in cui l'argomento è rappresentato da

(... )(... )(... ) restituisce un elenco di tre cose:

  ⍵≠0 Booleano in cui l'argomento differisce da 0
  ⍸¨ɩ ndices di quelli per ciascun elenco secondario
  ϵ nlist (appiattisci) da combinare in un unico elenco

  ⍵~¨0 rimuovere zeri da ciascun sottoelenco dell'argomento
  d← negozio che come d
  ≢¨  tally ogni
  +\ somma cumulativa
  0, anteporre uno zero

  ∊dϵ nlist (appiattisci) d per combinare in un unico elenco

  


* Per eseguire in Dyalog Classic, è sufficiente sostituirlo con ⎕U2378.


Bene, non capisco il formato di input però? f 4 4⍴e poi i valori?
Pureferret,

@Pureferret il codice definisce la funzione f. L'ingresso è in realtà un REPL, che chiama fsul risultato di 4 4⍴…cui r eshapes i dati in una matrice 4 × 4.
Adám,

1
Rho per r eshapes. Capisco!
Pureferret,

1
@Pureferret Ho aggiornato il Provalo online! link per mostrare meglio i casi di test.
Adám,

2

PHP , 107 byte

<?for($y=[$c=0];$r=$_GET[+$l++];)foreach($r as$k=>$v)!$v?:[$x[]=$v,$z[]=$k,$y[$l]=++$c];var_dump($x,$y,$z);

Provalo online!

PHP , 109 byte

<?$y=[$c=0];foreach($_GET as$r){foreach($r as$k=>$v)if($v){$x[]=$v;$z[]=$k;$c++;}$y[]=$c;}var_dump($x,$y,$z);

Provalo online!


Questo ha bisogno che i numeri siano stringhe?
Pureferret,

1
@Pureferret Qualsiasi input in PHP è una stringa o una matrice di stringhe. Non ho trasmesso l'input, quindi se desideri che l'output sia puramente int, sostituiscilo $x[]=$v con$x[]=+$v
Jörg Hülsermann,

2

JavaScript (ES6), 117 byte

a=>[a.map((b,i)=>(b=b.filter((x,c)=>x&&o.push(c)),m[i+1]=m[i]+b.length,b),m=[0],o=[]).reduce((x,y)=>x.concat(y)),m,o]

L'input è un array 2D di numeri e l'output è un array di [A, IA, JA].

spiegato

a=>[
    a.map((b,i) => (                                // map each matrix row
            b = b.filter((x,c) => x                 // filter to only non-zero elements
                && o.push(c)                        // and add this index to JA
            )
            m[i+1] = m[i] + b.length,               // set next value of IA
            b                                       // and return filtered row
        ),
        m=[0],o=[]                          // initialize IA (m) and JA (o)
    ).reduce((x,y) => x.concat(y)),                 // flatten the non-zero matrix
m,o]                                                // append IA and JA

test


1

Python 2 , 115 byte

lambda m:zip(*[[v,i]for k in m for i,v in enumerate(k)if v])+[reduce(lambda a,b:a+[len(b)-b.count(0)+a[-1]],m,[0])]

Provalo online!

L'output è [A, JA, IA]


1

Perl 6 , 84 byte

{.flatmap(*.grep(+*)),(0,|[\+] .map(+*.grep(+*))),.flat.kv.flatmap:{$^a%.[0]xx?$^b}}

Provalo online!

È presente l'argomento matrice singola $_.

  • .flatmap(*.grep(+*)) seleziona gli elementi diversi da zero dell'intera matrice.
  • [\+] .map(+*.grep(+*))è la riduzione triangolare del numero di elementi in ciascuna riga (che alcune lingue chiamano scan). (0,|...)antepone uno zero a tale elenco.
  • .flat.kvproduce un elenco indicizzato di tutti gli elementi della matrice. .flatmap: { $^a % .[0] xx ?$^b }mappe piatte sul modulo di ciascun indice in base al numero di colonne nell'array ( .[0], il numero di elementi nella prima riga), replicato dall'elemento stesso, interpretato come un valore booleano. Ossia, gli elementi diversi da zero vengono replicati una volta e zero elementi vengono replicati zero volte (ovvero rimossi).

1

Python + SciPy, 79 byte

immagino che i built-in non fossero vietati

from scipy.sparse import*
A=csr_matrix(input())
print A.data,A.indptr,A.indices

Accetta input nel formato [[0, 0, 0, 0],[5, 8, 0, 0],[0, 0, 3, 0],[0, 6, 0, 0]]


1

Japt , 31 27 byte

Accetta l'input come una matrice di array e restituisce una matrice di array.

[Uc f U®£X©NpYÃZèÃå+ iT NÅ]

Test ( -Qflag solo a scopo di visualizzazione)


Spiegazione

Input implicito di array U.
[[1,1,1],[1,1,1],[1,1,1]]

Uc f

Per il primo sub = -array, abbiamo appiattito ( c) Ue quindi filtrato ( f), rimuovendo tutti gli elementi false (ovvero, 0s)
[1,1,1,1,1,1,1,1,1]

U®         Ã

Costruiremo gli altri 2 sotto-array contemporaneamente, mappandoci sopra U.

£     Ã

Mappiamo su ogni elemento (sotto-array) in U

Xè l'elemento corrente dell'array secondario corrente ed ©è logico AND ( &&) quindi, se Xnon è vero (non zero) la parte successiva non verrà eseguita.

NpY

In Japt, Nè un array che contiene tutti gli input, quindi qui, se Xè vero, spingiamo ( p) l'indice ( Y) dell'elemento corrente su N.
[[[1,1,1],[1,1,1],[1,1,1]],0,1,2,0,1,2,0,1,2]

Tornando alla mappa dell'array principale e, per ogni elemento ( Z), otteniamo il conteggio degli elementi in quell'array secondario che sono veritieri (non zero).
[3,3,3]

å+

Ridurre cumulativamente questo array sommando.
[3,6,9]

iT

Inserisci ( i) 0 all'indice 0 per completare il secondo array secondario.
[0,3,6,9]

Per il sub-array finale, abbiamo semplicemente tagliato Ndal primo elemento.
[0,1,2,0,1,2,0,1,2]


Ho appena eseguito gli altri esempi e funziona
Pureferret
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.