lua"#"の長さの問題
5535 ワード
lua5.2にはgetn関数がありません.では、よく使われる長さの取り方は#で、#の使い方には注意すべき点があります.まずluaには配列部分とhashテーブル部分の2つの部分があることを明らかにします.基本的にすべての操作は先配列後hashテーブルです.local test 1={1,2,3,4,5}print(#test 1)印刷結果:5 local test 1={1,3,5,2,4}print(#test 1)印刷結果:5(いいでしょう....もちろん上と同じ配列の値です....)local test 1={[1]=1,[2]=2,[3]=3,[4]=4,[5]=5}print(#test 1)印刷結果:5(ここでtableには配列部分がなくhash表部分のみ)local test 1={[1]=1,[3]=3,[4]=4,[6]=6,[2]=2}print(#test 1)印刷結果:6 for i=1,#test 1 do print(test 1[i])endすべて印刷されると、1 2 3 4 nil 6書いたtableの中に5つの要素しかないのに、どうして6になったんだろう...ここの原因はluaソースコードの実現を見なければならない.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
やはり先配列で、配列には後hash部分がありません.hashテーブル部分の長さについて
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
j++はjがhash部分の最初の値であることを保証し、jからj位置が値がある場合はjを2倍に拡大し、2倍後にhashテーブルから値がない場所が見つかるまでhashテーブルから値を取ることができるかどうかを確認し、この値はiからjの区間にある.そして、iからjの間に見つかった最後のnilを半分に折って探します.前はその長さです.見損なう.luaH_getintはconst TValue*luaH_を取得するために使用されます.getint(Table*t,int key)は、その宣言から見ると、2番目のパラメータはkeyであり、keyによってvalueを取るが、外部から伝わるkeyが++の操作であることから、計算長さを探しているこのkeyは整形に違いないし、連続していなければならない(必ずしもそうではない).△もちろんこれは細部を究めずに誤認を実現するために少し見た分析です...さらに検証すると、local test 1={1,3,[4]=4,[6]=6,[2]=2}print(#test 1)印刷結果:2つまり上のソースコードでは、先に配列部分を遍歴し、配列部分があれば終了し、hash表部分local test 1={[4]=4,[6]=6,[2]=2}print(#test 1)印刷結果:0配列の後の1位はj++であり、valueがnilであれば、iが0であるjは1の戻り値が0である2つを一緒に見る:local test 1={[1]=1,[2]=2,[4]=4,[6]=6}print(#test 1)local test 1={[1]=1,[2]=2,[5]=5,[6]=6}print(#test 1)の2つの出力結果は6と2であり、しかも1つ目を印刷すると1 2 3 4 nil 6の中間差が1つで後ろに出てくるので、差が2つではだめwhy?上のソースコードのアルゴリズムのためです.例を挙げるとlocal test 1={[1]=1,[2]=2,[3]=3,[4]=4,[6]=6}最初のwhileループが終了し,i==4,j==8となり,以下の折半検索(詳細はやはり筆算にしましょう..)最後にi==6になりlocal test 1={[1]=1,[2]=2,[5]=5,[6]=6}最初のwhileサイクル後、i==2,j==4、折半して検索してi==2ということになりますが、これが分からないと、実際に操作している間に、変な問題に遭遇して多くの時間を浪費してしまいます...最後にlocal test 1={['a']=1,['b']=2,['c']=3}print(#test 1)印刷結果:0 keyは整形しなければならない.他の配列長形式は文字列や他の形式であれば、ループpairsという形式で取ったほうがいいです.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int
luaH_getn (Table *t) {
unsigned
int
j = t->sizearray;
if
(j >
0
&& ttisnil(&t->array[j -
1
])) {
/* there is a boundary in the array part: (binary) search for it */
unsigned
int
i =
0
;
while
(j - i >
1
) {
unsigned
int
m = (i+j)/
2
;
if
(ttisnil(&t->array[m -
1
])) j = m;
else
i = m;
}
return
i;
}
/* else must find a boundary in hash part */
else
if
(isdummy(t->node))
/* hash part is empty? */
return
j;
/* that is easy... */
else
return
unbound_search(t, j);
}
やはり先配列で、配列には後hash部分がありません.hashテーブル部分の長さについて
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static
int
unbound_search (Table *t, unsigned
int
j) {
unsigned
int
i = j;
/* i is zero or a present index */
j++;
/* find `i' and `j' such that i is present and j is not */
while
(!ttisnil(luaH_getint(t, j))) {
i = j;
j *=
2
;
if
(j > cast(unsigned
int
, MAX_INT)) {
/* overflow? */
/* table was built with bad purposes: resort to linear search */
i =
1
;
while
(!ttisnil(luaH_getint(t, i))) i++;
return
i -
1
;
}
}
/* now do a binary search between them */
while
(j - i >
1
) {
unsigned
int
m = (i+j)/
2
;
if
(ttisnil(luaH_getint(t, m))) j = m;
else
i = m;
}
return
i;
}
j++はjがhash部分の最初の値であることを保証し、jからj位置が値がある場合はjを2倍に拡大し、2倍後にhashテーブルから値がない場所が見つかるまでhashテーブルから値を取ることができるかどうかを確認し、この値はiからjの区間にある.そして、iからjの間に見つかった最後のnilを半分に折って探します.前はその長さです.見損なう.luaH_getintはconst TValue*luaH_を取得するために使用されます.getint(Table*t,int key)は、その宣言から見ると、2番目のパラメータはkeyであり、keyによってvalueを取るが、外部から伝わるkeyが++の操作であることから、計算長さを探しているこのkeyは整形に違いないし、連続していなければならない(必ずしもそうではない).△もちろんこれは細部を究めずに誤認を実現するために少し見た分析です...さらに検証すると、local test 1={1,3,[4]=4,[6]=6,[2]=2}print(#test 1)印刷結果:2つまり上のソースコードでは、先に配列部分を遍歴し、配列部分があれば終了し、hash表部分local test 1={[4]=4,[6]=6,[2]=2}print(#test 1)印刷結果:0配列の後の1位はj++であり、valueがnilであれば、iが0であるjは1の戻り値が0である2つを一緒に見る:local test 1={[1]=1,[2]=2,[4]=4,[6]=6}print(#test 1)local test 1={[1]=1,[2]=2,[5]=5,[6]=6}print(#test 1)の2つの出力結果は6と2であり、しかも1つ目を印刷すると1 2 3 4 nil 6の中間差が1つで後ろに出てくるので、差が2つではだめwhy?上のソースコードのアルゴリズムのためです.例を挙げるとlocal test 1={[1]=1,[2]=2,[3]=3,[4]=4,[6]=6}最初のwhileループが終了し,i==4,j==8となり,以下の折半検索(詳細はやはり筆算にしましょう..)最後にi==6になりlocal test 1={[1]=1,[2]=2,[5]=5,[6]=6}最初のwhileサイクル後、i==2,j==4、折半して検索してi==2ということになりますが、これが分からないと、実際に操作している間に、変な問題に遭遇して多くの時間を浪費してしまいます...最後にlocal test 1={['a']=1,['b']=2,['c']=3}print(#test 1)印刷結果:0 keyは整形しなければならない.他の配列長形式は文字列や他の形式であれば、ループpairsという形式で取ったほうがいいです.