|
▼T.K さん:
T.K さん、全文引用は紙面がもったいないから、やめましょう。
>▼kanabun さん:
>ありがとうございます。ここまでの説明でちょっとずつ仕組みが分かりました。
>細かい部分がまだ分からないですが、続きの解説楽しみにしています。
Dictionaryの概略が分かっていただけたら、
ではコード【72606】の説明のつづきです。
[Sheet1]
2 chr1 1048371 1049797 ER_1_Carrol
3 chr1 1054645 1055778 ER_2_Carrol
4 chr1 1285749 1286349 ER_3_Carrol
5 chr1 243097903 243098610 ER_396_Carrol
6 chr1 243121865 243122466 ER_397_Carrol
7 chr1 243604797 243605398 ER_398_Carrol
8 chr2 250722 251323 ER_399_Carrol
9 chr2 1650212 1650812 ER_400_Carrol
10 chr2 1660654 1661254 ER_401_Carrol
11 chr3 58431890 58432547 ER_756_Carrol
12 chr3 61588283 61588993 ER_757_Carrol
13 chr3 61595330 61595989 ER_758_Carrol
14 chr3 61605662 61606263 ER_759_Carrol
15 chr3 61649269 61649870 ER_760_Carrol
16 chr3 61768126 61769266 ER_761_Carrol
17 chr3 62137944 62138544 ER_762_Carrol
まず
> v = Intersect(r, r.Offset(1)).Value
を実行することにより、
[Sheet1]の2行目から17行目までが配列として変数vに代入されます。
つぎに
'------------------------------------------------------- (code)
> For i = 1 To UBound(v)
> If Not dic.Exists(v(i, 1)) Then
> Set dic(v(i, 1)) = _
> CreateObject("Scripting.Dictionary")
> End If
> dic(v(i, 1))(v(i, 4)) = Array(v(i, 2), v(i, 3))
> Next
'-----------------------------------------------------------
でやっていることは、昨日ちょっと触れたように、
日本語にすると、
'----------------------------------------------------- (日本語)
If 「dic にA列のclass名が Key登録されていなかったら」
→ dic のなかに子供の辞書を作成する
End If
dic(A列のclass名)のなかの 子供辞書の(D列ID)のKeyラベル
をもつ容器に 配列(B列の数値, C列の数値) を容れる、
'-----------------------------------------------------------
というようなことの繰り返しです。
一番最初のデータ i = 1(表の2行目のデータ)
> 2 chr1 1048371 1049797 ER_1_Carrol
に即していえば、
上のコードは、
'----------------------------------------------------- (code)
For i = 1 のとき
> If Not dic.Exists("chr1") Then
> Set dic("chr1") = CreateObject("Scripting.Dictionary")
> End If
> dic("chr1")("ER_1_Carrol") = Array(1048371, 1049797)
'-----------------------------------------------------------
をやっているということです。
For i = 1 を実行した後
↓親dic
┏━━━━━━━━━━━━━━━━━━━━━━━
┃ ↓子のDictionary
[chr1]┃ ┌─────────────
┃[ER_1_Carrol]│{1048371, 1049797}
┃ └─────────────
┃
┗━━━━━━━━━━━━━━━━━━━━━━━
という構造になります。(今度は図を横にしました)
つぎに、For i = 2 を実行した後は
↓親dic
┏━━━━━━━━━━━━━━━━━━━━━━━
┃ ┌─────────────
┃[ER_1_Carrol]│{1048371, 1049797}
┃ └─────────────
[chr1]┃ ┌─────────────
┃[ER_2_Carrol]│{1054645, 1055778}
┃ └─────────────
┃
┗━━━━━━━━━━━━━━━━━━━━━━━
となります。
以下同様にして、17行目(i = 16) まで繰り返したあとは dicは
こういう構造になります。(↓図は 最後のほうだけ示します)
[chr3]┃ └─────────────
┃ ┌─────────────
┃[ER_760_Carrol] │{61649269, 61649870}
┃ └─────────────
┃ ┌─────────────
┃[ER_761_Carrol] │{61768126, 61769266}
┃ └─────────────
┃ ┌─────────────
┃[ER_762_Carrol] │{62137944, 62138544}
┃ └─────────────
┗━━━━━━━━━━━━━━━━━━━━━━━
dic内には 3つのKey ("chr1","chr2","chr3") があり、
各Keyは それぞれ別の(独自の)子Dictionary をもつ --- このような
構成になります。
以上で、あたりチェックのSheet1側の範囲表データがDictionary
に登録されました。
これで、たとえば、"chr3" class の ID "ER_760_Carrol" の範囲は
dic("chr3")("ER_760_Carrol")
に配列として格納されていますから、
dic("chr3")("ER_760_Carrol")(0) とすれば start値が、
dic("chr3")("ER_760_Carrol")(1) とすれば end値を得ること
ができます。
さて、
> Dim a1, a2
> Dim b1, b2
> Dim vv
以降でやっていることは
> Set r = Worksheets("Sheet2").Cells(1).CurrentRegion
> With Intersect(r, r.Offset(1))
> v = .Resize(, 3).Value
> vv = .Columns(4).Cells.Value
> End With
で、
[Sheet2]
class start end ID
chr1 61649566 61649584
chr2 61649566 61649584
chr3 61649566 61649584
の1行目を除いたのち、
A,B,Cの3列を 変数v に格納し、
さらに4列目のID用に(現在空白セルの)4列目だけを 変数vv に入れ
たあと、
> For i = 1 To UBound(v) 'Sheet2 2行目から
> vv(i, 1) = Empty
たとえば i = 3 のとき、
> chr3 61649566 61649584
v(i,1) v(i,2) v(i,3)
という変数とデータの関係になってますから、
↓辞書dicに "chr3" というKeyが存在したら
> If dic.Exists(v(i, 1)) Then
↑は「真」となり、以下を実行します。
まず、
a1 に 2列目のstart値 61649566を、
a2 に 3列目のend値 61649584 を覚えておき↓、
> a1 = v(i, 2)
> a2 = v(i, 3)
dicのほうから class が "chr3" の子辞書内の
すべてのIDの start値と end値をb1,b2 として
a1,a2範囲との当たり判定をチェックしていきます。
> For Each ID In dic(v(i, 1)).Keys()
> b1 = dic(v(i, 1))(ID)(0)
> b2 = dic(v(i, 1))(ID)(1)
ここのところを iが3 の時の実数例で示せば、
> For Each ID In dic("chr3").Keys()
▼
最初のIDは "ER_756_Carrol"ですから、
> b1 = dic("chr3")("ER_756_Carrol")(0)
> b2 = dic("chr3")("ER_756_Carrol")(1)
は
b1 = 58431890
b2 = 58432547
になります。
これと
a1 = 61649566
a2 = 61649584
とで重なる部分の判定をします。
判定方法は前々回まとめたように
---------------------------------------- 判定の手順
> b1とa1をくらべて、
> ●b1 のほうが小さいときは、a1がb2より小さければ「あたり」
> (言い換えると「b1 <= a1 <b2 の関係にある」とき→あたり)
>
> a1
> b1───────b2
>
> ●a1 のほうが小さいときは、b1がa2より小さければ「あたり」
> (言い換えると「a1 < b1 <a2 の関係にあるとき」→あたり)
>
> a1━━━━━━━a2
> b1
------------------------------------------------------
という考えを用います。
最初のID ="ER_756_Carrol" のばあい、
> b1とa1をくらべて、
とは、b1 = 58431890 と a1 = 61649566 を比べることになります。
この結果、b1のほうが小さいので、次に a1と b2を比べますが、
b2のほうがa1より小さいので、このIDは「ハズレ」となります。
:
:
こんな調子で
> For Each ID In dic("chr3").Keys()
▼
に従って、IDをループしていくと、
▼"chr3" class 内で、ID = "ER_760_Carrol" のときは、
b1 = 61649269
b2 = 61649870
で、このときは
「 b1 <= a1 で、さらに、a1 < b2 の関係が成立」 します。
なので、このときのIDの値を vv(i,1)に代入して、
"chr3" 内のIDのLoop を中断(Exit For)します。
こうして、
> [Sheet2]
> chr1 61649566 61649584
> chr2 61649566 61649584
> chr3 61649566 61649584
のすべての行について、
各行の start値,end値(a1,a2) が
[Sheet1]の同名のclass内のID範囲(b1,b2)と比べて、
重なるIDがあればその値を vv(i) に入れ、
どれとも重ならなければ vv(i)には「ハズレ」を記入します。
最後に メモリ内のvv配列をシートの(2行目,4列目)以降に貼り
付けます.
↓範囲r内の 2行目4列目のセルのこと
> r.Item(2, 4).Resize(UBound(vv)).Value = vv
↑vvの最大要素数で 3 が返る
だいたい、こういう流れです。
|
|