Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 10 Home : Excel 2016)
A列が重複している場合C列を配列に格納する
投稿日時: 23/01/10 22:22:42
投稿者: goudoufu

現在、A列を配列に格納していますが、
A列が重複したデータの2つ目以降について
C列のデータを新しい配列に格納したいです。
良い方法があればご教示ください。
 
A B    C
1 みかん オレンジ
2 りんご 赤
1 ぶどう 紫
2 もも  ピンク
1 すいか 緑
 
A列は配列arrに格納済み
A列がかぶっているデータについて
C列を新しい配列newArrに格納したい
こうなるイメージ→ newArr=Array(紫,ピンク,緑)

回答
投稿日時: 23/01/11 10:09:19
投稿者: simple

コードを提示することはたぶん可能ですが、その前に少しコメントを。
 
(1)配列に入れたあと、それをどのように使うのですか?
   質問は余り細切れにせず、作業の目的(少なくとも後続処理)を説明したあとで
   具体論に入ったほうがよいと思いますよ。
   (そのほうが見通しがよいのと、別のより良い方法があるかもしれないので。)
(2)配列が必須な理由も併せて説明ください。行数はどの程度なんですか?
(3)ご自分ではどこまで出来ているかも書いていただくとよいと思います。
 
・重複しているかどうかの判定ということならば、
  dictionaryに、処理済みのものを登録していき、
  その都度、その値が処理済みかどうかを判定させるというのがよいかもしれません。
  (ワークシート上で、COUNTIFを使って、直前の行までに存在しているかどうかを判定してから、
  という方法もあるでしょうか。)
 
・配列に入れていくのであれば、動的配列の利用ということになります。
  http://officetanaka.net/excel/vba/variable/08.htm
  などのことはご存じなんでしょうか?

回答
投稿日時: 23/01/11 11:14:40
投稿者: Suzu

simple さん が仰っている事と重複しますが
 

引用:
こうなるイメージ→ newArr=Array(紫,ピンク,緑)

この結果を得るには、色々な方法が思いつきます。
でも、その配列を得るのは、それは 全体処理の中の一部です。
 
処理全体を見たときに、
それよりも 好ましい 手法があり、
引用:
こうなるイメージ→ newArr=Array(紫,ピンク,緑)

この結果の配列を使う必要が無いかもしれません。
 
前回の質問
https://www.moug.net/faq/viewtopic.php?t=81979
から察するに、XMLのノード解析の一部であり、
Excelの一般機能での XMLの書出し機能があっても、VBAでの書出しを行っている事から
VBA のみ での 処理を目指されている様ですが
 
1. D2 =COUNTIF(A$2:A2,"= "&A2) ↓方向オートフィル
2. オートフィルター D列 1以外 の値
3. オートフィルター結果に対しD列選択
4. 結果の列に対し Transpose関数適用し、1次元配列取得
 
Excel機能 の組み合わせを使う方法もあるのです。
XML にしても、EXCEL の機能を使いつつ、その部分がユーザーに見せない様にし
結果のみを ユーザーに提示 する事も選択肢と思います。

投稿日時: 23/01/11 13:18:50
投稿者: goudoufu

ご回答ありがとうございます。
現在仕事の昼休み中で、今日中にPC上から確認しつつ
返事ができないかもしれないので、
取り急ぎスマホから、大雑把な回答になり申し訳ありません。
 
配列格納後の利用は、ご推測のとおり
XMLの処理です。
重複した不要なノードを削除するのですが
その際の指定方法として、配列を利用したいと考えました。
(そこ以外はうまく動くようになっている)
 
Dictionaryで作りかけていたのですがうまくいかず
取り急ぎ質問してしまいました。
現状をお伝えしたほうが良いとのこと、
また、時間が取れ次第、実際に確認して
コメントします。
 
ありがとうございます

投稿日時: 23/01/11 13:22:39
投稿者: goudoufu

度々すみません。
配列を使いたいというのは勉強の意味もありました。
ブック上の関数で処理して、そのあと配列格納する方法なら自分でもできそうです。
そちらが効率的であればそちらで作成したいと思います。
ちなみに件数は多くて20件くらいだと思います。
 
Dictionary も改めて時間ができたら確認してみます

回答
投稿日時: 23/01/11 19:18:39
投稿者: simple

回答拝見致しました。
# 追記があるまで待ったほうがよいかもしれませんが。
 
多数のデータをシートに書き込むとかであれば、
配列にしておいて一括して書き込むことで処理速度の向上が見込めます。
ただ20行程度であれば、あえて配列にするメリットもないかと思います。
既にご指摘のとおりでしょう。
 
配列やdictionaryの学習用として、以下、下記します。
 
配列を使うとすれば、動的配列を、ひとつずつ大きさを拡大していくのが一般的です。
これに沿ったものが下記の test1です。
 
しかし、この場合は、上限が明確なので、最初に大きめの配列を作成しておき、
最後に使わなかった部分を縮小させたほうが簡便でしょう。
それが下記の test2です。
 
参考にして下さい。
 

Sub test1()
    Dim lastRow As Long
    Dim dic As Object
    Dim mat() As String
    Dim s As String
    Dim firstFlag As Boolean
    Dim k As Long
    
    Set dic = CreateObject("Scripting.Dictionary")
    
    lastRow = Cells(Rows.Count, "A").End(xlUp).row
    firstFlag = True
    
    For k = 1 To lastRow
        s = Cells(k, "A")
        If Not dic.exists(s) Then
            dic(s) = Empty
        Else
            If firstFlag Then
                 ReDim mat(0)
                 mat(0) = Cells(k, "C")
                 firstFlag = False
            Else
                ReDim Preserve mat(UBound(mat) + 1)
                mat(UBound(mat)) = Cells(k, "C")
            End If
        End If
    Next
    Stop '' 変数内容確認目的
End Sub

 
Sub test2()
    Dim lastRow As Long
    Dim dic As Object
    Dim mat() As String
    Dim s As String
    Dim k As Long, j As Long

    Set dic = CreateObject("Scripting.Dictionary")

    lastRow = Cells(Rows.Count, "A").End(xlUp).row
    ReDim mat(1 To lastRow)
    For k = 1 To lastRow
        s = Cells(k, "A").Value
        If Not dic.exists(s) Then
            dic(s) = Empty
        Else
            j = j + 1
            mat(j) = Cells(k, "C")
        End If
    Next
    ReDim Preserve mat(1 To j) '必要な分だけに縮める
    Stop '' 変数内容確認目的
End Sub

 
なお、重複を除いて抽出するフィルタオプションが適当かもしれませんね。

回答
投稿日時: 23/01/12 09:29:48
投稿者: Suzu

	A	B	C
1	A	B	C
2	1	みかん	オレンジ
3	2	りんご	赤
4	1	ぶどう	紫
5	2	もも	ピンク
6	1	すいか	緑

 
があったとして
 
引用:
1. D2 =COUNTIF(A$2:A2,"= "&A2) ↓方向オートフィル
2. オートフィルター D列 1以外 の値
3. オートフィルター結果に対しD列選択
4. 結果の列に対し Transpose関数適用し、1次元配列取得

 
の処理としては
Sub Sample()
  Dim vv As Variant

  Range("D1") = "D"

  Range( _
    Range("D2"), _
    Cells(Cells(Rows.Count, "A").End(xlUp).Row, "D") _
      ).Formula = "=COUNTIF(A$2:A2,""= ""&A2)"
  Range("A1").AutoFilter 4, "<>1"

  With Range("A1").CurrentRegion.Offset(1, 0)
    vv = _
      Excel.Application.WorksheetFunction.Transpose( _
        .Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Columns(3) _
        )
  End With
End Sub

こんな感じかと。
 
でも、
引用:
A列が重複したデータの2つ目以降について
C列のデータを新しい配列に格納

は、全体の処理の中の一部ですよね。
 
不要なモノを消すとか、データ解析 をする上で オートフィルターはとても有効な機能です。
 
ここだけの処理でオートフィルターを使うのではなく
全体の処理のなかでも、使える部分があると思います。
 
そういう意味でも simpleさんも当方も
goudoufuさんの質問を実現させるコードは すぐ提示できたけれども提示していなかったのです。
 
勉強と言う事でコード提示をしましたが、
VBAでゴリ押す前に、にExcel自体 の機能を使えば 処理全体を効率的に処理できる事が多いので
この配列 を得た後 どう使うのか まで気にしていた次第です。
 
ワークシートに展開後、D列 に 作業用の数式を入れ オートフィルターを使う
の様に 組み合わせれば 処理できる事も増えますので、一考されてはどうでしょうか。

回答
投稿日時: 23/01/16 12:51:57
投稿者: simple

コメントにいったん返事をしていただきたいですね。
もし不明点があれば継続して質問してください。
もう関心がなくなったのであれば、閉じてもらえますか?

トピックに返信