Ich habe kürzlich einen gepostet Add-In, um jeden Start von JMP zu protokollieren .
Als ich es entwickelte, dachte ich, ich sei schlau, die Protokollierungsinformationen als zu speichern assoziatives Array .
Hier ist ein Beispiel dafür, was in einer einzelnen Protokolldatei enthalten ist.
["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"]
Ein assoziatives Array sorgt dafür, dass sich das Protokoll selbst dokumentiert, da jedes Datenelement beschriftet wird. Dadurch wird das Protokoll auch erweiterbar. So können Sie in Zukunft problemlos weitere Informationen zu den Protokollen hinzufügen und jedes vorhandene Programm wird diese entweder anpassen oder ignorieren.
Es ist ziemlich einfach, ein Verzeichnis voller Protokolldateien wie folgt in eine Liste assoziativer Arrays einzulesen:
logfiles = Files In Directory( "./Logs" );
logs = {};
For( i = 1, i <= N Items( logfiles ), i++,
Insert Into( logs, Parse( Load Text File( "./Logs/" || logfiles[i] ) ) )
);
Daraus ergibt sich eine Struktur, die wie folgt aussieht:
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"]
};
Woran ich jedoch nicht gedacht habe, ist, dass es nicht ganz so einfach ist, diese Liste assoziativer Arrays in eine Datentabelle mit nach den Schlüsseln benannten Spalten und einer Zeile für jedes Element in der Liste umzuwandeln. Das geht mit vielen Schleifen über die Liste und die Arrays, aber ich habe auf etwas Eleganteres gehofft.
Also habe ich etwas Ähnliches getan wie viele von Ihnen, indem ich eine Frage im Diskussionsforum gepostet habe. Ich schickte eine E-Mail an unser Entwicklungsteam und andere Experten bei SAS und fragte, wie sie es machen würden.
Am 6. Juni 2017 um 18:16 Uhr schrieb Jeff Perkinson:
list_of_associative_arrays = {
[ „Schlüssel1“ => "A" , „Schlüssel2“ => "B" ],
[ „Schlüssel1“ => "C" , „Schlüssel2“ => "D" ],
[ „Schlüssel2“ => "F" , „Schlüssel1“ => „e“ , „key3“ => "G" ],
};
Wie würden Sie dies in diese Datentabelle umwandeln?
Beachten Sie ein paar Dinge:
- Die Spalten werden basierend auf den Schlüsseln der Arrays benannt
- Die Schlüssel erscheinen in unterschiedlicher Reihenfolge
- Die Anzahl der Schlüssel in jedem assoziativen Array variiert
Ich hatte gehofft, Folgendes zu bekommen:
- JSL, das beim Lesen relativ einfach zu interpretieren war.
- JSL, das relativ einfach zu schreiben war und die wenigsten Anweisungen enthielt.
- Effizienz (mäßig) ohne viel Schleifen.
Aber einige andere lieferten interessante Ideen, die es wert sind, erkundet zu werden.
@brady_brady hatte ein paar Lösungen.
Einer davon war ein kreativer Hacker, der sich auf ein stark strukturiertes Problem stützte und die Schlüssel und Werte in Textzeichenfolgen und dann in eine Datentabelle umwandelte, die er manipulierte.
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>Der andere war, in seinen eigenen Worten, nicht aufregend und hatte ein Paar verschachtelter Schleifen. Beachten Sie jedoch die Verwendung von Datentabellen-Skripten in der Schlussanweisung. Das werden Sie auch in unserer erfolgreichen Lösung wieder sehen.
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>
Das ist wirklich clever, da es die implizite Schleife in der ausnutzt
J()-Funktion . Dies ist ein Trick, den ich immer wieder vergesse, den ich mir aber immer zu merken versuche. Allerdings hat er diese letzte Schleife und noch einige andere
Ausdruck() Funktionen, die das Lesen erschweren.
Außerdem gibt er zu, getäuscht zu haben, indem er angenommen hat, dass die Schlüssel einheitlich benannt sind. Ich verzeihe das, da es sich um ein Problem handelt, das leicht mit einer Schleife über die von ihm erstellte Datenstruktur gelöst werden kann:
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>
Das gefällt mir, weil die letzte Schleife über der Datentabelle verläuft und das Datentabellen-Scripting verwendet, das wir zum ersten Mal gesehen haben
@brady_brady 's Lösung. Sie sind vielleicht anderer Meinung, aber für mich fühlt sich das besser an, als eine Schleife über eine JSL-Datenstruktur zu durchlaufen. Vielleicht liegt es daran, dass es weniger Zeichen enthält, was die Lesbarkeit erleichtert.
Aber er benutzt ein paar klobig
Während() Schleifen, um die Schlüssel abzurufen und die Spalten zu benennen. Als Gewinner nehme ich also eine Kombination aus
@Craige_Hales ' Und
@Joseph Morgan Die Lösungen:
// 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>
Wenn die J()-Funktion – und ihre implizite Schleife – das Lesen für Sie erschwert, @Joseph Morgan weist darauf hin, dass es durch eine For()-Schleife ersetzt werden könnte.
for( i=2,i<=nitems(list),i++, unique<<INSERT></INSERT>
Für mich war es wirklich lehrreich, jede Lösung zu studieren und eine Reihe von Tricks zu sehen, die ich später vielleicht anwenden kann. Nehmen Sie sich etwas Zeit und tun Sie dasselbe für sich.
Wie bei jeder Sprache gibt es viele Möglichkeiten, dasselbe zu erreichen. Jedes hat seine Vorteile. Der Trick besteht darin, sie zu kennen und dort anzuwenden, wo sie am vorteilhaftesten sind.
Hi. Ich habe das durchgelesen und es kommt mir komplizierter vor, als es sein müsste. Ich habe es geschafft, die unten stehende Lösung zum Laufen zu bringen, mit ziemlich wenig Code und sie kann wahrscheinlich mit mehr Aufwand noch etwas weiter reduziert werden.
//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
Ich bin auf ein paar Probleme mit dem empfohlenen Ansatz im ursprünglichen Beitrag gestoßen, die mit dieser Schleife zusammenhängen, in der Werte für jede Zeile in die Tabelle eingefügt werden:
<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>
- Dies wird ausgelöst, sobald in einem der assoziativen Arrays (Zeilen) ein fehlender Wert (oder das Fehlen eines Schlüssels) festgestellt wird.
- Fügt den Tabellenspalten nur Zeichenfolgedaten (Zeichendaten) hinzu.Alle numerischen Daten in der Quelle werden einfach ignoriert, was zu leeren Spalten mit numerischen Werten führt.
- Die Spaltentypen werden als Zeichen belassen und nicht auf numerisch umgestellt, wenn vollständig numerische Daten auftreten.
Am Ende habe ich Folgendes herausgefunden, was diese Probleme zu lösen scheint:
aaListToDataTable = function ({aaList}, {Default Local},
unique=aaList[1];
for (i=1, i<=nitems(aaList), i++,
unique<<INSERT></INSERT>Die Leistung bei besonders großen Datensätzen wurde nicht getestet.
Wow, @Jeff_Perkinson Und @Phil_Brown , ich bin auf der Suche nach allgemeinem Wissen über die Indizierung durch assoziative Arrays und habe so viel mehr gefunden!
Als kürzlicher Konverter zu assoziativen Arrays (so viele verschachtelte Listen in meiner Vergangenheit
) Ich versuche, sie häufiger zu verwenden, und allein in diesem Thread müssen mindestens vier separate Ideen vorhanden sein, die ich in verschiedene Sätze meines Codes integrieren kann!
Danke, dass du das gepostet hast 
Sehr interessant! Wenn ich noch einen anderen Ansatz vorschlagen darf, der dem von Brady ähnelt, aber etwas anders ist.
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;