나는 최근에 각 JMP 실행을 기록하는 추가 기능 .
개발하면서 로깅 정보를 연관 배열 .
다음은 단일 로그 파일에 있는 내용의 예입니다.
["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"]
연관 배열은 각 데이터 조각에 레이블이 지정될 때 로그를 자체 문서화합니다. 또한 로그를 확장할 수 있습니다. 따라서 앞으로는 로그에 더 많은 정보를 쉽게 추가할 수 있으며 기존 프로그램은 이를 적용하거나 무시합니다.
로그 파일로 가득 찬 디렉토리를 다음과 같이 연관 배열 목록으로 읽는 것은 매우 쉽습니다.
logfiles = Files In Directory( "./Logs" );
logs = {};
For( i = 1, i <= N Items( logfiles ), i++,
Insert Into( logs, Parse( Load Text File( "./Logs/" || logfiles[i] ) ) )
);
결과적으로 다음과 같은 구조가 됩니다.
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"]
};
하지만 내가 생각하지 못한 것은 연관 배열 목록을 목록의 각 항목에 대한 키와 행의 이름을 따서 명명된 열이 있는 데이터 테이블로 변환하는 것이 쉽지 않다는 것입니다. 목록과 배열에 대해 많은 반복을 수행할 수 있지만 좀 더 우아한 것을 원했습니다.
그래서 저는 토론 포럼에 질문을 게시하여 많은 분들이 하는 것과 유사한 작업을 수행했습니다. SAS의 개발 팀과 다른 전문가들에게 어떻게 할 것인지 묻는 이메일을 보냈습니다.
2017년 6월 6일 오후 6시 16분에 Jeff Perkinson은 다음과 같이 썼습니다.
list_of_associative_arrays = {
[ "키1" => "ㅏ" , "키2" => "비" ],
[ "키1" => "씨" , "키2" => "디" ],
[ "키2" => "에프" , "키1" => "이자형" , "키3" => "g" ],
};
이것을 이 데이터 테이블로 어떻게 변환하시겠습니까?
몇 가지 사항에 유의하십시오.
- 열은 배열의 키를 기반으로 이름이 지정됩니다.
- 키가 다른 순서로 나타납니다.
- 각 연관 배열의 키 수는 다양합니다.
나는 다음을 얻고 싶었습니다.
- 읽을 때 비교적 해석하기 쉬운 JSL.
- JSL은 상대적으로 작성하기 쉬웠고 명령문이 가장 적었습니다.
- 루핑이 많지 않은 효율성.
그러나 다른 사람들은 탐색할 가치가 있는 흥미로운 아이디어를 제공했습니다.
@brady_brady 몇 가지 해결책이 있었습니다.
하나는 고도로 구조화된 문제에 의존하고 키와 값을 텍스트 문자열로 변환한 다음 그가 조작한 데이터 테이블로 변환하는 창의적인 해킹이었습니다.
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 = {
["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>
이것은 암시적 루프를 활용한다는 점에서 정말 영리합니다.
J() 함수 . 이것은 내가 계속 잊고 있지만 항상 기억하려고 노력하는 트릭입니다. 그러나 그는 최종 루프와 여러
특급() 읽기 어렵게 만드는 기능.
또한 그는 키의 이름이 일관되게 지정되어 있다고 가정하여 부정 행위를 인정합니다. 그가 만든 데이터 구조에 대한 루프로 쉽게 극복할 수 있는 문제이므로 용서하겠습니다.
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>
마지막 루프가 데이터 테이블 위에 있고 우리가 처음 본 데이터 테이블 스크립팅을 사용하기 때문에 이것이 마음에 듭니다.
@brady_brady 의 솔루션입니다. 동의하지 않을 수도 있지만 JSL 데이터 구조를 반복하는 것보다 더 나은 느낌입니다. 아마도 글자 수가 적어서 읽기가 더 쉽기 때문일 것입니다.
// 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>
J() 함수와 암시적 루프로 인해 읽기가 더 어려워지면 @joseph_morgan For() 루프로 대체될 수 있다고 지적합니다.
for( i=2,i<=nitems(list),i++, unique<<INSERT></INSERT>
이것은 각 솔루션을 연구하고 나중에 사용할 수 있는 여러 요령을 여기에서 보는 데 정말 유익했습니다. 시간을 갖고 자신을 위해 똑같이 하십시오.
다른 언어와 마찬가지로 동일한 작업을 수행하는 방법이 많이 있습니다. 각각의 장점이 있습니다. 트릭은 그것들을 알고 가장 유리한 곳에 적용하는 것입니다.
안녕하세요. 나는 이것을 읽고 있었고 필요 이상으로 복잡하다고 느낍니다. 나는 아래의 솔루션을 작동시킬 수 있었고 코드의 양은 매우 적었으며 더 많은 노력을 기울이면 아마도 조금 더 줄일 수 있을 것입니다.
//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 />
);제이크
값이 각 행에 대해 테이블에 삽입되는 이 루프와 관련하여 원래 게시물의 권장 접근 방식과 관련하여 몇 가지 문제가 발생했습니다.
<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>
- 연관 배열(행) 중 하나에서 누락된 값(또는 키가 없음)이 발견되는 즉시 발생합니다.
- 문자열(문자) 데이터만 테이블 열에 추가합니다.숫자인 소스의 모든 데이터는 무시되므로 값이 숫자인 빈 열이 생성됩니다.
- 열 유형은 문자로 남아 있으며 전체가 숫자 데이터인 경우 숫자로 강제 변환되지 않습니다.
나는 이러한 문제를 해결하는 것으로 보이는 다음과 같이 끝났습니다.
aaListToDataTable = function ({aaList}, {Default Local},
unique=aaList[1];
for (i=1, i<=nitems(aaList), i++,
unique<<INSERT></INSERT>특히 대규모 데이터 세트에 대한 성능을 테스트하지 않았습니다.
우와, @제프_퍼킨슨 그리고 @Phil_Brown , 연관 배열을 통한 인덱싱에 대한 몇 가지 일반적인 내용을 찾고 있었고 훨씬 더 많은 정보를 얻었습니다!
최근에 연관 배열로 변환(과거에는 중첩된 목록이 너무 많았습니다. ) 나는 그것들을 더 자주 사용하려고 노력하고 있으며 이 스레드에만 적어도 4개의 개별 아이디어가 있어야 합니다. 다양한 코드 세트로 병합할 수 있습니다!
게시해주셔서 감사합니다 
나는 또한 얼마나 많은 요소가 있는지 알 필요가 없다는 사실을 좋아합니다. While( IsEmpty(...) )을 사용하면 배열 길이를 동적으로 설정할 수 있습니다.
매우 흥미로운! Brady와 비슷하지만 약간 다른 또 다른 접근 방식을 제안할 수 있습니다.
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;