限定しりとり

簡単な例でご説明します。
A1=あ、B1=会う、C1=合う、D1=安芸、E1=秋、F1=空き
A2=い、B2=言う、C2=居る、D2=胃
A3=う、B3=鵜、 C3=撃つ


のようにA列を見出し語としたランダムな単語を集めた表があります。
列方向の単語数は差があり凹凸のある表となっています。
それぞれ見出しにたいする列方向の単語には重複語が混在しています。
重複を除外する処理プログラムを作りたい。
たとえは
B1=会う、C1=合う、D1=安芸、E1=秋、F1=空き、G1=会う
のリストからG1を削除処理するプログラムを連想配列を使って組みたいのですが、
自力で一行だけの処理は出来ましたが、全部の行を処理できません。
大きな単語表のためFor...Nextのループ処理では時間がかかるので、なんとか
連想配列での高速処理をしたいと悪戦苦闘しています。
連想配列は、Key対Itemの2元配列は高速処理ができるが、上記の一覧表の処理には不向きなのでしょうか?ヒントを頂けると助かります。
なお、当方の環境は、
Windows10
Excel2016
VBA歴1年半のレベルです。

質問者からの補足コメント

  • HAPPY

    プログラムの実例ありがとうございます。
    見出し語が、構成語の中に重複している行のデータが残ってしまうので、
    rの範囲を1行からに定義し、sh2への連想配列の書き出し先をCells(1,1)からのResize(,k)
    に変更して実行しました。
    頂きました回答の解釈を通して連想配列を使いコツをつかみたいと思います。
    回答のプログラムに対する質問者の解釈:
    1)変数iで1行単位の配列を読み込み
    2)構成単語の前後の空白をTrim(n)で削除して
    3)作りつつある連想配列に既に登録なければobjDic.Exists(Trim(n)) で
      連想配列objDicのkeyに単語を登録する。
    *補足2にて継続します。

    No.1の回答に寄せられた補足コメントです。 補足日時:2019/01/14 16:47
  • うれしい

    *補足2:
    4)上記の見出し語との重複を処理対象とするための変更として
      (a)処理対象変更
    'Set r = Range(Cells(i, 2), Cells(i, Columns.Count).End(xlToLeft))  ’2⇒1に変更
       Set r = Range(Cells(i, 1), Cells(i, Columns.Count).End(xlToLeft))
      (b)出力変更
        'sh2.Cells(i, 1).Resize(, k).Value = ar   ’2⇒1に変更
       sh2.Cells(i, 1).Resize(, k).Value = ar
      としました。
    5)結果:4800見出し行、構成語38476を処理して4800見出し行、38400の構成語となり、76語の重複語を削除できました。
    *補足3へ継続します。

      補足日時:2019/01/14 16:53
  • うれしい

    *補足3:自力でここまで連想配列が使えるようになりたので、このプログラムを参考にさせて頂き勉強します。追加の質問で恐縮ですが、今後のために教えてください。
    Q1:3)の連想配列に記録する際時、
      objDic.Add Trim(n), j
      のitemは、jを対で登録するが実態はj=0で
      Dim j as Longを宣言せず、
      objDic.Add Trim(n), ""
      でも良いのでしょうか?
    Q2:For Each...Nextで処理するときにIn Rangeの範囲での全nを対象に処理させる使い方を知っていますが、
    For Each n In Application.Index(r.Value, 1, 0)
    のIndex()は、初めてみました。Index()の定義をオンラインHelpで調べても見つかりません。VBEの中でとか調べる方法も解 りません。
    *補足4にて継続

      補足日時:2019/01/14 16:56
  • HAPPY

    *補足4:ヒントで結構です。「わからないメソッドなどは、***を見よ!」のようなコメントで
       教えて頂けると助かります。
    PS
    VBAの勉強を始めてから1年半ですが、何とか皆さんの足元に近づけるよう知識を得たいと願ってます。
    ===以上です。よろしくお願いいたします。

      補足日時:2019/01/14 16:58

A 回答 (2件)

こんばんは。



最初に、

>For Each n In Application.Index(r.Value, 1, 0)
>のIndex()は、初めてみました。Index()の定義をオンラインHelpで調べても見つかりません。VBEの中でとか調べる方法も解りません。

これは、私が見つけたのか、それとも誰かに教わったのか、もう覚えていません。この原点は、Excel Ver.4 にあります。Macro関数は、配列の出力をするのですが、通常のVBAでは拾うことができません。それを配列関数で拾うのです。これは、Excel4Macro で使用する時も同じで、1対1でしか取れないと教えている人がいますが、それは間違いです。マクロ関数など、もう遠い彼方の話ですが、私は、一応、マニュアルは残してあります。

なお、これが、横なら、縦は Transpose です。2次元を1次元に直すことによって、VBA関数やMatch関数などが使えるようになります。

また、Application.Index と、WorksheetFunction.Index との違いとかは、もう教えてくれる人がいません。Application.Index など、Application 直結の場合は、関数自体にエラー値を吐き出しますが、WorksheetFunction の場合は、VBAエラーとなってしまいます。当然、IsError でエラー値の判別が可能です。

>「わからないメソッドなどは、***を見よ!」
教えて!gooにはあまりこの手の使い手がいませんが、OkWaveにはまだ残っていると思います。私の書いたものは裏技に該当しますが、あまり追いかけようとはしないほうがいいのかもしれません。

かつては、「教えて!goo」で学べたものが、調べてみると、国内の掲示板にも書籍などにもどこにも載っていないとか、悔しいですね。Win APIの使い方などを、披露する人も少なくなりました。私の新技術のRibbon Customizer の使い方は、Ka-net (https://www.ka-net.org/blog/) がもとになっています。

>何とか皆さんの足元に近づけるよう知識を得たいと願ってます。
新しくVBAに参入する人は、どんどん新しいものを取り入れてください。過去のものに引きずられても、それらの価値は低いです。今回のものは、例えば、.Net FrameWork の
System.Collections.ArrayList を使ってもよいわけです。

また、JavaScript などの技術は無視できませんし、今度は、Python とか、また、VB.Net やC# は、今後のExcelプログラミングの必須課題になってくると思います。

先に進んでいる人は、もうとうの昔に「教えて!goo」の内容など卒業しています。もう私などは、少しも先に進みません。Microsoft の通例で、新しいものについていけない人たちは切り捨てになってくのが宿命ですから、頑張って前向きに進むしかありません。

近年で、私が、もっとも衝撃的だったのは、AriawaseというExcel用のツールをみた時です。途中までは同じようにできたけれども、1歩も2歩も先に行っているだけでなく、もう枠組み自体が違っているわけです。https://github.com/vbaidiot/ariawase (vbaidiotはハンドル・日本人です)

後回しになりましたが、
> objDic.Add Trim(n), j
> のitemは、jを対で登録するが実態はj=0で
> Dim j as Longを宣言せず、
> objDic.Add Trim(n), ""
> でも良いのでしょうか?
       Key, Item
objDic.Add Trim(n), ""

本来は、Item のなかは、String型の単語などを入れるようになっていたかのように思います。CStr(j)などが相応しいかもしれません。しかし、今試してみましたら、問題はなかったようですね。

私の書き方は、VBA用のテンプレートを30個ぐらい用意してありますので、そこから引っぱり出して、それを貼り付けて加工しています。

Trim(n), ""
ちなみに、Trim はなぜ入れているか分かりますか?
掲示板で書いている人たちは、無視したがる傾向が強いです。

なお、変なアドバイスかもしれませんが、買える書籍は、積ん読でよいので、手にいれたほうがよいです。後で後悔するよりもよいです。役にたたないかもしれないけれども、役に立つこともあるのです。変わった内容だと思うものは、何とか自分のもとに置いとくのがよいです。欲を言えば、旧VB6の知識やテクニックは、VBAで生きています。絶版でも手に入るひとつに、Visual Basicによる『はじめてのアルゴリズム入門』技術評論社は、今後、どんな言語になっても、基礎は同じです。もはや古臭い内容なのに、時々力を発揮する、また掲示板で語られない内容のひとつです。

補足欄からの回答で抜けている部分がありましたら、ご容赦ください。指摘があれば、また書きます。
    • good
    • 0
この回答へのお礼

高齢になってからはじめたソフトウエア言語の世界で、出会うことが一つ一つ目新しく感動的です。
おしえてGooを卒業してる方たちが、きっと私の身近で活躍しているのでしょう。これもうれしいことです。
VBAを知って使い始めて1年半です。根っからの欲張りなので、未熟なVBAを入り口にしてython、JavaScripやVB.Netに手を出して、読める本は片っ端から購入しむさぼり読み進めています。
今回、第二回目の回答をいただき、感動しています。技術開発に従事していた現役時代から「同じ会社である必要はなく、同じ業界の人たちが連携すれば、開発能力は無制限!」海外の仲間たちとの合言葉でした。今夜また、そんな思いに馳せています。
返信をくださったWindFaller様、そしてきっと良き仲間達に深く感謝します。皆様の幸多かれと祈願します!
今回は、本当に良き回答を頂きましたことに深く御礼申し上げます。

お礼日時:2019/01/15 21:06

こんばんは。



難しい話はわからないけれども、「連想配列」を使って、重複単語を削除するなら、こんなふうにしたらどうでしょうか。配列は、1次元にしてしまいました。出力は、以下はSheet2 になっています。また、高速処理という話には、まったく自信がありません。
まだ、直すところ(配列変数に渡している所を直接してしまうとか)はあるとは思いますが、試し的に作りました。

'//
Sub DupplicateDel()
 Dim objDic As Object 'New Scripting.Dictionary
 Dim r As Range
 Dim i As Long, n As Variant, j As Long, k As Long
 Dim ar As Variant
 Dim sh2 As Worksheet: Set sh2 = Worksheets("Sheet2") '出力シート

 Set objDic = CreateObject("Scripting.Dictionary")
 For i = 1 To Cells(Rows.Count, 1).End(xlUp).Row
  Set r = Range(Cells(i, 2), Cells(i, Columns.Count).End(xlToLeft))
  For Each n In Application.Index(r.Value, 1, 0)
   If objDic.Exists(Trim(n)) = False Then
    objDic.Add Trim(n), j
   End If
  Next n
  Application.ScreenUpdating = False
  ar = objDic.keys()
  k = UBound(ar) + 1
  sh2.Cells(i, 1).Value = Cells(i, 1).Value
  sh2.Cells(i, 2).Resize(, k).Value = ar
  objDic.RemoveAll
  Application.ScreenUpdating = True
 Next i
 Beep
End Sub
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!