Di recente ho pubblicato un componente aggiuntivo per registrare ogni avvio di JMP .
Mentre lo stavo sviluppando, ho pensato di essere intelligente memorizzando le informazioni di registrazione come file matrice associativa .
Ecco un esempio di cosa c'è in un singolo file di registro.
["Bitness" => "64-bit",
"Build Information" => "Jan 9 2017, 00:53:08, Release, JMP ",
"Date" => "06/06/2017 08:05:03 AM",
"Host" => "Windows",
"Hostname" => "computer1",
"JMP Version" => "13.1.0",
"Product Name" => "Standard",
"Username" => "joeuser"]
Un array associativo rende il registro autodocumentante poiché ogni dato viene etichettato. Rende anche il registro estensibile. Quindi, in futuro puoi facilmente aggiungere ulteriori informazioni ai registri e qualsiasi programma esistente lo adatterà o lo ignorerà.
È abbastanza facile leggere una directory piena di file di registro in un elenco di array associativi come questo:
logfiles = Files In Directory( "./Logs" );
logs = {};
For( i = 1, i <= N Items( logfiles ), i++,
Insert Into( logs, Parse( Load Text File( "./Logs/" || logfiles[i] ) ) )
);
Ciò si traduce in una struttura simile a questa:
logs = {
["Bitness" => "64-bit",
"Build Information" => "Jan 9 2017, 00:53:08, Release, JMP ",
"Date" => "06/06/2017 02:53:43 PM",
"Host" => "Windows",
"Hostname" => "MFIDT0259",
"JMP Version" => "13.1.0",
"Product Name" => "Standard",
"Username" => "pol"],
["Bitness" => "64-bit",
"Build Information" => "Jan 9 2017, 00:53:08, Release, JMP ",
"Date" => "06/06/2017 08:30:03 AM",
"Host" => "Windows",
"Hostname" => "MFIDT0259",
"JMP Version" => "13.1.0",
"Product Name" => "Standard",
"Username" => "pol"]
};
Quello a cui non ho pensato però è che non è così facile convertire quell'elenco di array associativi in una tabella di dati con colonne denominate dopo le chiavi e una riga per ogni elemento nell'elenco. Può essere fatto con molti cicli sull'elenco e sugli array, ma speravo in qualcosa di un po' più elegante.
Quindi, ho fatto qualcosa di simile a quello che molti di voi fanno postando una domanda nel forum delle discussioni. Ho inviato un'e-mail al nostro team di sviluppo e ad altri esperti di SAS chiedendo come avrebbero fatto.
Il 6 giugno 2017, alle 18:16, Jeff Perkinson ha scritto:
list_of_associative_arrays = {
[ "chiave1" => "UN" , "chiave2" => "B" ],
[ "chiave1" => "C" , "chiave2" => "D" ],
[ "chiave2" => "F" , "chiave1" => "e" , "chiave3" => "G" ],
};
Come convertiresti questo in questa tabella di dati?
Nota alcune cose:
- Le colonne sono denominate in base alle chiavi degli array
- Le chiavi appaiono in ordini diversi
- Il numero di chiavi in ogni array associativo varia
Speravo di ottenere:
- JSL che era relativamente facile da interpretare durante la lettura.
- JSL relativamente facile da scrivere, con il minor numero di istruzioni.
- Efficienza (ish) senza molti loop.
Ma altri hanno fornito idee interessanti che vale la pena esplorare.
@brady_brady aveva un paio di soluzioni.
Uno era un hack creativo che contava su un problema altamente strutturato e convertiva le chiavi ei valori in stringhe di testo e poi in una tabella di dati che manipolava.
l = {
["key1" => "c", "key2" => "d", "key3" => "g2", "key4" => "h"],
["key1" => "a", "key2" => "e", "key3" => "g3", "key4" => "o"],
["key1" => "b", "key2" => "f", "key3" => "g1", "key4" => "i"],
["key1" => "c", "key2" => "a", "key3" => "g6", "key4" => "k"]
};
nt = New Table( "x", new column("Column 1", character), new column("Group", character) );
n_l = nitems(l);
n_k = nitems(l[1]<<GET keys="">,]")[2::2*n_l*n_k::2];
refs = words(char(l), "{} [\!"=>,]")[1::2*n_l*n_k-1::2];
column(nt,1)<<SET values=""></SET></GET>L'altro era, nelle sue stesse parole, poco entusiasmante e aveva un paio di anelli annidati. Tuttavia, si noti l'uso dello scripting della tabella dati nell'istruzione finale. Lo vedrai di nuovo nella nostra soluzione vincente.
l = {
["key1" => "a", "key2" => "b"],
["key2" => "f", "key1" => "e", "key3" => "g"],
["key1" => "c", "key2" => "d", "key4" => "h"],
["key2" => "f2", "key1" => "e2", "key3" => "g2"]
};
nt = New Table( "challenge" );
colList = {};
For( i = 1, i <= N Items( l ), i++,
nt << addrows( 1 );
ki = l[i] << get keys;
For( j = 1, j <= N Items( ki ), j++,
If( !Contains( colList, ki[j] ),
nt << New Column( ki[j], character );
Insert Into( colList, ki[j] );
);
Column( nt, ki[j] )[i] = l[i][ki[j]];
);
);
nt << delete column( 1 );
l = {
["key1" => "a", "key2" => "b"],
["key1" =>"c", "key2" => "d"],
["key2" => "f", "key1" => "e", "key3" => "g"]
};
// get unique column names – alas, cannot just count items in associative arrays
colnm=l[1]; i=1;
j(nitems(l),1,colnm<<INSERT></INSERT>
Questo è davvero intelligente in quanto sfrutta il ciclo implicito nel file
funzione J() . Questo è un trucco che continuo a dimenticare ma cerco sempre di ricordare. Tuttavia, ha quel ciclo finale e un numero di
Espr() funzioni che ne rendono più difficile la lettura.
Inoltre, ammette di aver imbrogliato assumendo che le chiavi abbiano un nome coerente. Lo perdonerò perché è un problema facilmente superabile con un ciclo sulla struttura dati che ha creato:
colnames=colnm<<GET keys=""></GET>
Ora, @Craige_Hales ' soluzione:
list = {
["key9" => "k9r1", "key2" => "k2r1"],
["key2" => "k2r2", "key1" => "k1r2", "key3" => "k3r2"],
["key1" => "k1r3", "key2" => "k2r3", "key4" => "k4r3"],
["key2" => "k2r4", "key1" => "k1r4", "key7" => "k7r4"]
};
nonunique = list<<GETKEYS></GETKEYS>
Mi piace perché il ciclo finale è sulla tabella dei dati e utilizza lo scripting della tabella dei dati che abbiamo visto per la prima volta
@brady_brady la soluzione di. Potresti non essere d'accordo, ma per me è meglio che eseguire il loop su una struttura di dati JSL. Forse è perché ci sono meno caratteri e questo rende più facile la lettura.
Ma usa un paio di goffi
Mentre() loop per ottenere le chiavi e nominare le colonne. Quindi, prenderò come vincitore una combinazione di
@Craige_Hales ' E
@Joseph Morgan le soluzioni di:
// Revised
list = {
["key9" => "k9r1", "key2" => "k2r1"],
["key2" => "k2r2", "key1" => "k1r2", "key3" => "k3r2"],
["key1" => "k1r3", "key2" => "k2r3", "key4" => "k4r3"],
["key2" => "k2r4", "key1" => "k1r4", "key7" => "k7r4"]
};
unique=list[1];
i=1;
j(nitems(list),1,unique<<INSERT></INSERT>
Se la funzione J() e il suo ciclo implicito rendono più difficile la lettura, @Joseph Morgan sottolinea che potrebbe essere sostituito con un ciclo For().
for( i=2,i<=nitems(list),i++, unique<<INSERT></INSERT>
Questo è stato davvero istruttivo per me per studiare ogni soluzione e vedere una serie di trucchi qui che potrei essere in grado di utilizzare in seguito. Prenditi del tempo e fai lo stesso per te stesso.
Come ogni lingua, ci sono molti modi per ottenere la stessa cosa. Ognuno ha i suoi vantaggi. Il trucco è conoscerli e applicarli dove sono più vantaggiosi.
Ciao. Stavo leggendo questo e sembra più complicato di quanto dovrebbe essere. Sono stato in grado di far funzionare la soluzione di seguito, una quantità di codice piuttosto minima e probabilmente può essere ulteriormente ridotta con uno sforzo maggiore.
//perc_array is my associative array. it has two levels if you want to call them that. the first is a text string, the second is numeric;<BR /><BR />perc_array= [1 => "Sum(Qty 1kHz)", 2 => "Sum(Qty 1KHZ_LT50)", 3 => "Sum(Qty 50Hz_High)", 4 => "Sum(Qty 50Hz_Low)", 5 => "Sum(Qty DC)", 6 => "Sum(Qty ERROR)", 7 => "Sum(Qty GA1GA2)", 8 => "Sum(Qty Idd)", 9 => "Sum(Qty Idd_Low)", 10 => "Sum(Qty THD)", "Sum(Qty 1kHz)" => 0.00202316156420758, "Sum(Qty 1KHZ_LT50)" => 0.000757081600136874, "Sum(Qty 50Hz_High)" => 0.0176374349048836, "Sum(Qty 50Hz_Low)" => 0.00692494412780564, "Sum(Qty DC)" => 0.00482906851160752, "Sum(Qty ERROR)" => 0.00296416694290878, "Sum(Qty GA1GA2)" => 0.124725985649668, "Sum(Qty Idd)" => 0.00232257236652159, "Sum(Qty Idd_Low)" => 0.000327213233957462, "Sum(Qty THD)" => 0.000032079728819359];<BR /><BR />//the denominator below is how many "columns" of keys you have or how many levels;
ncheck=n items(perc_Array())/2;<BR /><BR />//xx is the variable I use to know how many "rows" i have in the associative array;
dt_sort=new table("SortFT", Add Rows( xx-1 ),
New Column( "Label", Character),
New Column( "%", Numeric, Format("Percent",2));
);
for(i=1, i<=ncheck, i++,
dt_sort:Label[i]=perc_array[i];
dt_sort:Name("%")[i]=perc_array[dt_sort:Label[i]];<BR />
);Jake
Ho riscontrato alcuni problemi con l'approccio consigliato nel post originale, relativo a questo ciclo in cui i valori vengono inseriti nella tabella per ogni riga:
<SPAN class="token function">foreachrow</SPAN><SPAN class="token punctuation">(</SPAN>
i <SPAN class="token operator">=</SPAN> <SPAN class="token function">row</SPAN><SPAN class="token punctuation">(</SPAN><SPAN class="token punctuation">)</SPAN><SPAN class="token punctuation">;</SPAN>
dt<SPAN class="token punctuation">[</SPAN>i<SPAN class="token punctuation">,</SPAN>list<SPAN class="token punctuation">[</SPAN>i<SPAN class="token punctuation">]</SPAN><SPAN class="token operator"><</SPAN><SPAN class="token operator"><</SPAN><SPAN class="token messages">getkeys] </SPAN><SPAN class="token operator">=</SPAN> list<SPAN class="token punctuation">[</SPAN>i<SPAN class="token punctuation">]</SPAN><SPAN class="token operator"><</SPAN><SPAN class="token operator"><</SPAN><SPAN class="token messages">getvalues</SPAN><SPAN class="token punctuation">;</SPAN>
<SPAN class="token punctuation">)</SPAN><SPAN class="token punctuation">;</SPAN>
- Questo genera non appena si incontra un valore mancante (o l'assenza di una chiave) in uno degli array associativi (righe).
- Aggiunge solo dati stringa (carattere) alle colonne della tabella.Tutti i dati nell'origine che sono numerici verranno semplicemente ignorati, risultando in colonne vuote in cui i valori sono numerici.
- I tipi di colonna vengono lasciati come caratteri e non vengono costretti a numerici se vengono rilevati dati interamente numerici.
Ho finito con quanto segue, che sembra risolvere questi problemi:
aaListToDataTable = function ({aaList}, {Default Local},
unique=aaList[1];
for (i=1, i<=nitems(aaList), i++,
unique<<INSERT></INSERT>Non l'ho testato per le prestazioni su set di dati particolarmente grandi.
Oh, @Jeff_Perkinson E @Phil_Brown , sono venuto alla ricerca di alcune cose generali sull'indicizzazione tramite array associativi e ho ottenuto molto di più!
Come recente conversione in array associativi (così tanti elenchi nidificati nel mio passato: \ ) Sto cercando di usarli più spesso e ci devono essere almeno 4 idee separate solo in questo thread che posso unire in vari set del mio codice!
Grazie per aver postato questo 
Molto interessante! Se posso offrire ancora un altro approccio, simile a quello di Brady ma leggermente diverso.
list = {
["key9" => "k9r1", "key2" => "k2r1"],
["key2" => "k2r2", "key1" => "k1r2", "key3" => "k3r2"],
["key1" => "k1r3", "key2" => "k2r3", "key4" => "k4r3"],
["key2" => "k2r4", "key1" => "k1r4", "key7" => "k7r4"]
};
newdt = New Table();
cols ={};
For( i = 1, i <= N Items( list ), i++,
newdt << addRows( 1 );
cKey = list[i] << first;
While( !Is Empty( cKey ),
If( !Contains(cols, cKey),
newdt << newColumn( cKey, Character );
InsertInto( cols, cKey);
);
Column( cKey )[i] = list[i][ckey];
cKey = list[i] << next( cKey );
);
);
newdt << deleteColumns( 1 );
newdt << reOrderByName;