[[20210325160624]] 『配列と配列の比較と結果のカウント値を配列に入れ』(maya) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『配列と配列の比較と結果のカウント値を配列に入れる』(maya)

いつもお世話になっています。
今回、どういったコードで作成していけばいいかまったくアイデアが浮かばず
、コーディングの方向性だけだけでも、示していただきたく投稿させていただきました。

[実現したいこと]

事前に作成した配列Aグループと、インプットボックスにて入力した連続した数字の値を、ある条件下で振り分けて、配列Bグループを作成し、配列Bと配列Aを比較して、一致すればプラス1、一致しなければマイナス1といった配列を作成し、最終的にはグラフで見れるようにしたいです。

※A1やらB1やらは、セル番地ではなく、グループの名称です。

***配列Aグループの作成**********

以下の配列に入っている数字は、事前に決めた定数です。

配列A1(配列A1に入る数字は、4つの数字の組み合わせです)
[0000, 1111, 0011, 1100, 0101, 1010, 0101]

配列A2(配列A2に入る数字は、6つの数字の組み合わせです)
[000000, 111111, 001100, 110011, 000111, 111000, 010101, 101010]

配列A3
[00000000, 11111111, 00110011, 11001100, 00001111, 11110000, 01010101, 10101010]

*******配列Bグループの作成*********

まずは、インプットボックスで、0と1を組み合わせたランダムな数字を入力します。

入力例)

「00001111」

入力された00001111を、以下の条件に従い、新しい配列を作成します。

配列B1(配列A1に入る数字は、4つの数字の組み合わせです)
入力された値を左からみて、4桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、0000をまずは仲間入り。次は1つずれて0001を仲間入り。
[0000, 0001, 0011, 0111, 1111]

配列B2(配列A1に入る数字は、6つの数字の組み合わせです)
入力された値を左からみて、6桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、000011をまずは仲間入り。次は1つずれて000111を仲間入り。
[000011, 000111, 001111]

00001111
配列B3(配列A1に入る数字は、8つの数字の組み合わせです)
入力された値を左からみて、8桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、今回はインプットボックスに入力された値が8桁だったので
[00001111]

*****配列Bと配列Aの比較と一致率の主力*******

?@配列B1と配列A1を比較

配列B1の値が

[0000, 0001, 0011, 0111, 1111]

の時に

配列A1の値

[0000, 1111, 0011, 1100, 0101, 1010, 0101]

と比較する。

配列B1に入っている値それぞれを、配列A1に入っている値すべてと比較して、一致すれば+1,一致していなければ-1といった値の配列を作成する。

(1)配列B1の一つ目の値

0000と配列A1[0000, 1111, 0011, 1100, 0101, 1010, 0101]を比較。
配列A1に0000があるので一致で+1。

(2)次に配列B1の2つ目の値

0001と配列A1[0000, 1111, 0011, 1100, 0101, 1010, 0101]を比較。
配列A1の値いずれとも一致しないので-1。

(3)結果

今回の場合だと、以下のような結果になります。
[+1, -1, +1, -1, +1]

?A配列B2と配列A2を比較

配列B2の値が

[000011, 000111, 001111]

の時に

配列A2の値

[000000, 111111, 001100, 110011, 000111, 111000, 010101, 101010]

と比較する。

(1)配列B2の一つ目の値

000011と配列A2[000000, 111111, 001100, 110011, 000111, 111000, 010101, 101010]を比較。いずれも一致しないので-1。

(2)結果

今回の場合だと、以下のような結果になります。
[-1, +1, -1]

?B配列B3と配列A3を比較

配列B3の値が

[00001111]

の時に

配列A3の値

[00000000, 11111111, 00110011, 11001100, 00001111, 11110000, 01010101, 10101010]

と比較する。

(1)配列B3の一つ目の値

[00001111]と配列A3[000000, 111111, 001100, 110011, 000111, 111000, 010101, 101010]を比較。いずれも一致しないので-1。

(2)結果

今回の場合だと、以下のような結果になります。
[+1]

****結果配列の作成*********

配列B1とA1の比較結果は以下でした。
[+1, -1, +1, -1, +1]
配列B2とA2の比較結果は以下でした。
[-1, +1, -1]
配列B3とA3の比較結果は以下でした。
[+1]

上記の結果を以下の以下の表にあてはめます。
インプットボックスに入れた値は[00001111]で8個の数字です。
なので8個の空の値がはいった配列
[0, 0, 0, 0, 0, 0, 0, 0]を3つ作成します。

配列B1とA1の比較結果は、インプットボックスに入れた値の[00001111]
左から4つ目から比較をはじめるため
空の配列へ比較結果[+1, -1, +1, -1, +1]を以下のように
[0, 0, 0, +1, -1, +1, -1, +1]
代入します。

配列B2とA2の比較結果は、インプットボックスに入れた値の[00001111]
左から6つ目から比較をはじめるため
空の配列へ比較結果[-1, +1, -1]を以下のように
[0, 0, 0, 0, 0, -1, +1, -1]
代入します。

配列B3とA3の比較結果は、インプットボックスに入れた値の[00001111]
左から8つ目から比較をはじめるため
空の配列へ比較結果[+1]を以下のように
[0, 0, 0, 0, 0, 0, 0, +1]
代入します。

最終的に作成した結果配列から、グラフを作成したいと思っています。
ちょっと長文なりますのでいったん投稿します。

< 使用 Excel:Excel2016、使用 OS:Windows10 >


<訂正>

訂正箇所以下

配列B1(配列B1に入る数字は、4つの数字の組み合わせです)
配列B2(配列B2に入る数字は、6つの数字の組み合わせです)
配列B3(配列B3に入る数字は、8つの数字の組み合わせです)

訂正後抜粋

*****配列Bグループの作成*********

まずは、インプットボックスで、0と1を組み合わせたランダムな数字を入力します。
入力例)
「00001111」
入力された00001111を、以下の条件に従い、新しい配列を作成します。
配列B1(配列B1に入る数字は、4つの数字の組み合わせです)
入力された値を左からみて、4桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、0000をまずは仲間入り。次は1つずれて0001を仲間入り。
[0000, 0001, 0011, 0111, 1111]
配列B2(配列B2に入る数字は、6つの数字の組み合わせです)
入力された値を左からみて、6桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、000011をまずは仲間入り。次は1つずれて000111を仲間入り。
[000011, 000111, 001111]
00001111
配列B3(配列B3に入る数字は、8つの数字の組み合わせです)
入力された値を左からみて、8桁になるところで、配列に仲間入りしたい。
※一番左端の0から参照し、今回はインプットボックスに入力された値が8桁だったので
[00001111]
(maya) 2021/03/25(木) 17:06

 素直に愚直な方法で作ってみました。試しに。
 たぶん主旨というか考え方はこれで合ってるんじゃないかと思いますが...

    Rem 文字列から配列Bを作成する関数
    Function CreateArrayB(String01 As String, Length As Long) As Variant()
        If Len(String01) < Length Then Exit Function
        Dim i As Long, Ary() As Variant
        ReDim Ary(0 To Len(String01) - Length)
        For i = 1 To Len(String01) - Length + 1
            Ary(i - 1) = Mid$(String01, i, Length)
        Next
        CreateArrayB = Ary
    End Function

    Rem 配列B1に入っている値それぞれを、配列A1に入っている値すべてと比較して、
    Rem 一致すれば+1,一致していなければ-1といった値の配列を作成する関数
    Function MatchTest(ArrayA() As Variant, ArrayB() As Variant) As Variant
        Dim i As Long, j As Long, Ary() As Variant
        ReDim Ary(LBound(ArrayB) To UBound(ArrayB))
        For i = LBound(ArrayB) To UBound(ArrayB)
            Ary(i) = -1&
            For j = LBound(ArrayA) To UBound(ArrayA)
                If ArrayB(i) = ArrayA(j) Then
                    Ary(i) = 1&
                    Exit For
                End If
            Next
        Next
        MatchTest = Ary
    End Function

    Rem 指定した要素数の配列を作って、ケツから順に引数1の配列の中身を転記して返す関数
    Function CreateArrayC(MatchRes() As Variant, Length As Long) As Variant
        Dim Ary() As Variant, i As Long, j As Long
        ReDim Ary(0 To Length - 1)
        j = UBound(MatchRes)
        For i = Length - 1 To 0 Step -1
            Ary(i) = 0&
            If j >= LBound(MatchRes) Then
                Ary(i) = MatchRes(j)
                j = j - 1
            End If
        Next
        CreateArrayC = Ary
    End Function

    Sub やってみる()
        Const str As String = "00001111"
        Dim AryA() As Variant
        Dim AryB() As Variant
        Dim Res() As Variant
        Dim AryC As Variant

        AryA = Array("0000", "1111", "0011", "1100", "1010", "0101")
        AryB = CreateArrayB(str, 4)
        Debug.Print Join(AryB, ",")
        Res = MatchTest(AryA, AryB)
        Debug.Print Join(Res, ",")
        AryC = CreateArrayC(Res, Len(str))
        Debug.Print Join(AryC, ",")
        Debug.Print

        AryA = Array("000000", "111111", "001100", "110011", "000111", "111000", "010101", "101010")
        AryB = CreateArrayB(str, 6)
        Debug.Print Join(AryB, ",")
        Res = MatchTest(AryA, AryB)
        Debug.Print Join(Res, ",")
        AryC = CreateArrayC(Res, Len(str))
        Debug.Print Join(AryC, ",")
        Debug.Print

        AryA = Array("00000000", "11111111", "00110011", "11001100", "00001111", "11110000", "01010101", "10101010")
        AryB = CreateArrayB(str, 8)
        Debug.Print Join(AryB, ",")
        Res = MatchTest(AryA, AryB)
        Debug.Print Join(Res, ",")
        AryC = CreateArrayC(Res, Len(str))
        Debug.Print Join(AryC, ",")

    End Sub

(白茶) 2021/03/25(木) 22:15


白茶 様

返信遅くなり申し訳ありません。
わあ〜まさかコーディングしていただけるとは。。
一度、コピペして動かしてみます!!!
コード内容1ずつ理解するのに時間かかるので、レス遅くなると思いますが
ひとまず、ありがとうございました!
(maya) 2021/03/26(金) 08:58


白茶様

おおお〜〜!!!
凄い。。私がやりたいこと完璧に実装されてました。
スキルアップするために、ちょっとコードの意味を1行ずつ
みながら勉強させていただきます。

ありがとうございました。
(maya) 2021/03/26(金) 09:04


白茶様

aryの4要素目からではなく、ケツからいれていくという手法。。。素晴らしすぎます。
この柔軟な思考ができればな〜コード一通り読ませていただき、理解しました。
本当にありがとうございました。

Rem 指定した要素数の配列を作って、ケツから順に引数1の配列の中身を転記して返す関数

    Function CreateArrayC(MatchRes() As Variant, Length As Long) As Variant
        Dim Ary() As Variant, i As Long, j As Long
        ReDim Ary(0 To Length - 1)
        j = UBound(MatchRes)
        For i = Length - 1 To 0 Step -1
            Ary(i) = 0&
            If j >= LBound(MatchRes) Then
                Ary(i) = MatchRes(j)
                j = j - 1
            End If
        Next
        CreateArrayC = Ary
    End Function

(maya) 2021/03/26(金) 16:36


 解決後ですみませんが、少し教えてもらえますか?

 今回の計算は、どんな背景というかジャンルで出てきている話なんでしょうか。
 後学のために教えていただけないですか?
 何か自然言語関係の計算かなにかなんでしょうか。
 機密でなければ、大雑把で結構なので、簡単にコメントしていただけないですか。

 これだけだと何ですので、
 私が書いたコードも付け足しで載せてみます。
 (並行して書いていたのです。
   既に適切な回答を頂いていますので、余り嬉しくないと思いますが。)

 Sub test()
     '基準文字列の配列
     Dim ctrl4, ctrl6, ctrl8
     ctrl4 = Split("0000,1111,0011,1100,0101,1010", ",")
     ctrl6 = Split("000000,111111,001100,110011,000111,111000,010101,101010", ",")
     ctrl8 = Split("00000000,11111111,00110011,11001100,00001111,11110000,01010101,10101010", ",")

     Dim s$
     Dim g4, v4, g6, v6, g8, v8

     '対象文字列
     s = "000011110101"

     '計算
     g4 = nGram(s, 4)    '4-Gramからなる配列
     v4 = compareArray(ctrl4, g4)
     g6 = nGram(s, 6)    '6-Gramからなる配列
     v6 = compareArray(ctrl6, g6)
     g8 = nGram(s, 8)    '8-Gramからなる配列
     v8 = compareArray(ctrl8, g8)

     'ワークシートへの書き出し
     Dim n As Long
     n = Len(s)
     Cells(1, 1).Resize(3).EntireRow.ClearContents
     Cells(1, 1).Resize(3, n).Value = 0
     Cells(1, 1).Offset(, n - (UBound(v4) + 1)).Resize(1, UBound(v4) + 1) = v4
     Cells(2, 1).Offset(, n - (UBound(v6) + 1)).Resize(1, UBound(v6) + 1) = v6
     Cells(3, 1).Offset(, n - (UBound(v8) + 1)).Resize(1, UBound(v8) + 1) = v8
 End Sub

 Function nGram(s As String, n As Long) As Variant
     Dim k&
     Dim ss As String
     For k = 0 To Len(s) - n
         ss = ss & "," & Mid(s, k + 1, n)
     Next
     nGram = Split(Mid(ss, 2), ",")
 End Function

 Function compareArray(ctrl As Variant, target As Variant) As Variant
     ReDim ary(0 To UBound(target))
     Dim m As Variant
     Dim k As Long

     For k = 0 To UBound(target)
         m = Application.Match(target(k), ctrl, 0)
         If Not IsError(m) Then
             ary(k) = 1
         Else
             ary(k) = -1
         End If
     Next
     compareArray = ary
 End Function

 なお、上記にでてくる、nGramというのは、N-Gramに由来したものの積もりです。
 (任意の文字列や文書を連続したn個の文字で分割するテキスト分割方法です)

(γ) 2021/03/26(金) 23:23


γ様

ご返信遅くなり申し訳ありません。
また、コンパクト化されたコードを提供いただき、ありがとうございます。
もしよろしければ、直接やりとりをさせていただくことは可能でしょうか。
当方がやりたいことを、ご説明させていただきます。

rei0079.qwp@gmail.com

お返事、お待ちしております。

(maya) 2021/04/19(月) 00:43


 どうも恐縮です。
 いえいえ、そこまでして頂くには及びません。
 こちらに書けないことまで知って益を得ようとは思っておりませんので。
 わざわざありがとうございました。

 なお、質問掲示板は、このサイト上でのみ完結すべきもので、
 水面下の情報のやりとりは適切ではないと考えております。
 今後もその方針の積もりです。

 # 老婆心ながら、個人情報は消された方がよいと思います。

(γ) 2021/04/19(月) 09:34


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.