6

Excel と VBA を使用して、厳密に VBA を使用して (ピボット テーブルを使用するのと同じ方法で) 配列内のデータを最適にフィルター処理する方法についてアドバイスが必要でした。現在存在するデータに基づいていくつかのデータ決定を行う UserForm を作成しています。私はそれを十分にうまく行う方法を視覚化できますが、VBA プログラミングに精通していません。

ここに例があります

A       B       C
bob     12      Small
sam     16      Large
sally   1346    Large
sam     13      Small
sally   65      Medium
bob     1       Medium

配列内のデータを取得するには、次を使用できます

Dim my_array As Variant

my_array = Range("A1").CurrentRegion

さて、私は 2D 配列をループすることに慣れていますが、2D 配列データを (配列を何度もループすることなく) フィルタリングする最も効果的な方法は何でしょうか?

たとえば、次のようなデータを取得するにはどうすればよいですか。

data_for_sally As Variant 'rows with sally as name in ColA
data_for_sally_less_than_ten As Variant ' all rows with sally's name in ColA and colB < 10
data_for_all_mediums as Variant ' all rows where ColC is Medium

提案?一連のカスタム関数とループを使用してこれを解決できましたが、もっと良い方法があるに違いないと思いました。ありがとう。

4

2 に答える 2

5

VBAのみを使用したいと思います。

主に次のようないくつかのパラメーターに依存すると思います。

  • どのくらいの頻度で同じ条件を実行しますか => フィルターの結果を保存しますか、それとも毎回再計算しますか?
  • どれくらいの頻度でフィルタリングする必要があるか => 頻繁に適切なコード構造を用意する価値がある場合、そうでない場合は、1 回限りのループが明らかに適しています。

OO の観点から、パフォーマンス (速度とメモリ) が問題ではないと仮定すると、次の設計に進みます (実装の詳細には立ち入らず、一般的なアイデアのみを示します)。このように使用できるクラス (想像力で ArrayFilter と呼びましょう) を作成します。

フィルターをセットアップする

Dim filter As New ArrayFilter
With filter
    .name = "sam"
    .category = "Medium"
    .maxValue = 10
End With

または

filter.add(1, "sam") 'column 1
filter.add(3, "Medium") 'column 3
filter.addMax(2, 10) 'column 2

フィルター処理されたデータ セットを作成する

filteredArray = getFilteredArray(originalArray, filter)

getFilteredArray は非常に簡単に記述できます。配列をループして、値がフィルターに一致するかどうかを確認し、有効な行を新しい配列に入れます。

If filter.isValidLine(originalArray, lineNumber) Then 'append to new array

長所

  • すっきりとしたデザイン
  • 特に列番号を使用する 2 番目のバージョンでは、再利用可能です。これは、実際に任意の配列をフィルタリングするために使用できます。
  • フィルタリング コードは、テストできる 1 つの関数にあります。
  • 結果: コードの重複を避ける

短所

  • 同じフィルタを 2 回使用しても、フィルタリングは毎回再計算されます。たとえば、結果を Dictionary に保存できます。以下を参照してください。
  • メモリ: getFilteredArray を呼び出すたびに新しい配列が作成されますが、とにかくこれを回避する方法がわかりません
  • これにより、かなりの数のコード行が追加されるため、コードの読み取り/保守が容易になる場合にのみ追加します。

ps: パフォーマンスを向上させるために結果をキャッシュする必要がある場合、1 つの方法は、結果を辞書に格納し、getFilteredArray 関数にロジックを追加することです。配列が非常に大きいか、同じフィルターを頻繁に実行しない限り、これはおそらく価値がないことに注意してください。

filters.add filter, filteredArray 'filters is a dictionary

そうすれば、次に getFilteredArray を呼び出すときに、次のようなことができます。

For each f in filters
    'Check if all conditions in f and newFilter are the same
    'If they are:
    getFilteredArray = filters(f)
    Exit Function
Next

'Not found in cache: compute the result
于 2012-05-04T14:56:32.903 に答える