11

Web のどこにも見つからないという問題があります (あるかもしれませんが、見つかりません)。

13 列のデータを含むスプレッドシートがあります。各列には、全体的なテスト ケースに入る必要があるパラメーターのバリエーションが含まれています。

のように、それらはすべて異なります。

E:
101%
105%
110%
120%

J:
アッパー S
アップサイド L
ダウンサイド B
プレミアム V

ネストされたループを使用する組み合わせの問題に対するいくつかの解決策を見てきました。13 個のネストされたループを避けたいと思います (ただし、現時点ではこれが最善の策です)。各列ですべての一意の組み合わせを生成する方法について、私はちょっと途方に暮れています。

それが皆さんにとって十分な意味があるかどうかはわかりません。誰かが少なくとも再帰アルゴリズムを使って正しい方向に向けてくれることを願っていました。さまざまな数の列と行を取るのに十分なほど動的にしたいと思います。

皆さんが私に与えることができる助けをありがとう。

4

5 に答える 5

22

私は ODBC アプローチを提供したので、これを行う方法がすぐには明らかではないため、詳しく説明する必要があると考えました。そして、正直なところ、私はプロセスを再学習し、それを自分で文書化する必要がありました.

これは、Excel と Microsoft Query を使用して、2 つ以上の 1 次元データ配列のデカルト積を生成する方法です。

これらの手順は XL2007 で書かれていますが、どのバージョンでもマイナーな変更 (もしあれば) で機能するはずです。

ステップ1

配列を列に編成します。

重要:以下の太字で示されているように、各列には 2 つの「ヘッダー」名が必要です。最上位の名前は、後で「テーブル名」として解釈されます。2 番目の名前は「列名」として解釈されます。これは、数ステップ後に明らかになります。

両方の「ヘッダー」を含む各データ範囲を順番に選択し、Ctrl+Shift+F3. Top row[名前の作成] ダイアログでのみチェックを入れ、 をクリックしますOK

すべての名前付き範囲が確立されたら、ファイルを保存します。

ここに画像の説明を入力

ステップ2

データ | データ 外部データを取得 | 他の情報源から | Microsoft クエリから

を選択し<New Data Source>ます。Choose New Data Sourceダイアログで:

  1. 接続のフレンドリ名

  2. 適切な Microsoft Excel ドライバーを選択します

... それからConnect

ここに画像の説明を入力

ステップ 3

Select Workbook...次に、ファイルを参照します。

ここに画像の説明を入力

ステップ 4

「テーブル」から「列」を追加します。これで、ステップ 1 の「2 つのヘッダー」レイアウトが重要である理由がわかります。これにより、ドライバーがだましてデータを正しく理解することができます。

次のクリックCancel(本当に!)。この時点で、"Microsoft Query で編集を続けますか?" というメッセージが表示される場合があります。(答えYes)、または結合するという苦情は、グラフィカル エディターで表現できません。これを無視して、鍛造します...

ここに画像の説明を入力

ステップ 5

Microsoft Query が開き、既定では、追加したテーブルがクロス結合されます。これにより、必要なデカルト積が生成されます。

ここで、MSQuery を完全に閉じます。

ここに画像の説明を入力

ステップ 6

ワークシートに戻ります。ほぼ完成です、約束します!にチェックNew worksheetを入れOKます。

ここに画像の説明を入力

ステップ 7

交差結合された結果が返されます。

ここに画像の説明を入力

于 2012-05-22T00:53:47.500 に答える
10

ループを嫌う理由がわかりません。この例を参照してください。1秒もかかりませんでした。

Option Explicit

Sub Sample()
    Dim i As Long, j As Long, k As Long, l As Long
    Dim CountComb As Long, lastrow As Long

    Range("G2").Value = Now

    Application.ScreenUpdating = False

    CountComb = 0: lastrow = 6

    For i = 1 To 4: For j = 1 To 4
    For k = 1 To 8: For l = 1 To 12
        Range("G" & lastrow).Value = Range("A" & i).Value & "/" & _
                                     Range("B" & j).Value & "/" & _
                                     Range("C" & k).Value & "/" & _
                                     Range("D" & l).Value
        lastrow = lastrow + 1
        CountComb = CountComb + 1
    Next: Next
    Next: Next

    Range("G1").Value = CountComb
    Range("G3").Value = Now

    Application.ScreenUpdating = True
End Sub

スナップショット

ここに画像の説明を入力

: 上記は小さな例です。それぞれ200行の4列でテストを行いました。このようなシナリオで可能な組み合わせの合計は1600000000で、16 秒かかりました。

このような場合、Excel の行制限を超えています。私が考えることができるもう 1 つのオプションは、このようなシナリオで出力をテキスト ファイルに書き込むことです。データが小さい場合は、配列を使用せずにセルに直接書き込む必要はありません。:) しかし、大きなデータの場合は、配列を使用することをお勧めします。

于 2012-05-21T23:10:34.163 に答える
5

私はこれを自分で何度か必要とし、最終的にそれを構築しました。

コードは、列の総数と、列内の任意の数の個別の値に対応していると思います (たとえば、各列には任意の数の値を含めることができます)。

各列のすべての値が一意であると想定しています (そうでない場合、重複した行が取得されます)。

現在選択しているセルに基づいて出力をクロス結合することを前提としています(必ずすべてを選択してください)

現在の選択の 1 列後に出力を開始することを前提としています。

仕組み (簡単に): 最初に各列と各行: N 列のすべてのコンボをサポートするために必要な合計行数を計算します (列 1 のアイテム * 列 2 のアイテム ... * 列 N のアイテム)

各列の 2 番目: 合計コンボ数と前の列の合計コンボ数に基づいて、2 つのループを計算します。

ValueCycles (現在の列のすべての値を循環する必要がある回数) ValueRepeats (列の各値を連続して繰り返す回数)

Sub sub_CrossJoin()

Dim rg_Selection As Range
Dim rg_Col As Range
Dim rg_Row As Range
Dim rg_Cell As Range
Dim rg_DestinationCol As Range
Dim rg_DestinationCell As Range
Dim int_PriorCombos As Long
Dim int_TotalCombos As Long
Dim int_ValueRowCount As Long
Dim int_ValueRepeats As Long
Dim int_ValueRepeater As Long
Dim int_ValueCycles As Long
Dim int_ValueCycler As Long

int_TotalCombos = 1
int_PriorCombos = 1
int_ValueRowCount = 0
int_ValueCycler = 0
int_ValueRepeater = 0

Set rg_Selection = Selection
Set rg_DestinationCol = rg_Selection.Cells(1, 1)
Set rg_DestinationCol = rg_DestinationCol.Offset(0, rg_Selection.Columns.Count)

'get total combos
For Each rg_Col In rg_Selection.Columns
    int_ValueRowCount = 0
    For Each rg_Row In rg_Col.Cells
        If rg_Row.Value = "" Then
            Exit For
        End If
        int_ValueRowCount = int_ValueRowCount + 1
    Next rg_Row
    int_TotalCombos = int_TotalCombos * int_ValueRowCount
Next rg_Col

int_ValueRowCount = 0

'for each column, calculate the repeats needed for each row value and then populate the destination
For Each rg_Col In rg_Selection.Columns
    int_ValueRowCount = 0
    For Each rg_Row In rg_Col.Cells
        If rg_Row.Value = "" Then
            Exit For
        End If
        int_ValueRowCount = int_ValueRowCount + 1
    Next rg_Row
    int_PriorCombos = int_PriorCombos * int_ValueRowCount
    int_ValueRepeats = int_TotalCombos / int_PriorCombos


    int_ValueCycles = (int_TotalCombos / int_ValueRepeats) / int_ValueRowCount
    int_ValueCycler = 0

    int_ValueRepeater = 0

    Set rg_DestinationCell = rg_DestinationCol

    For int_ValueCycler = 1 To int_ValueCycles
        For Each rg_Row In rg_Col.Cells
            If rg_Row.Value = "" Then
                Exit For
            End If

                For int_ValueRepeater = 1 To int_ValueRepeats
                    rg_DestinationCell.Value = rg_Row.Value
                    Set rg_DestinationCell = rg_DestinationCell.Offset(1, 0)
                Next int_ValueRepeater

        Next rg_Row
    Next int_ValueCycler

    Set rg_DestinationCol = rg_DestinationCol.Offset(0, 1)
Next rg_Col
End Sub
于 2012-11-14T18:39:41.097 に答える
3

私の2番目のコメントに基づく解決策。この例では、3 つの列のデータがあることを前提としていますが、より多くのデータを処理するように適応させることができます。

サンプルデータから始めます。便宜上、一番上の行にカウントを追加しました。また、組み合わせの総数 (カウントの積) も追加しました。これはSheet1次のとおりです。

ここに画像の説明を入力

オンSheet2:

ここに画像の説明を入力

式:

A2:C2(オレンジ色のセル) はハードコードされています=0

A3=IF(SUM(B3:C3)=0,MOD(A2+1,Sheet1!$E$1),A2)

B3=IF(C3=0,MOD(B2+1,Sheet1!$G$1),B2)

C3=MOD(C2+1,Sheet1!$J$1)

D2=INDEX(Sheet1!$E$2:$E$5,Sheet2!A2+1)

E2=INDEX(Sheet1!$G$2:$G$6,Sheet2!B2+1)

F2=INDEX(Sheet1!$J$2:$J$5,Sheet2!C2+1)

Total行 3 から表示されている行数まで入力してくださいSheet1

于 2012-05-21T22:20:07.027 に答える
0

メソッドを呼び出して現在のレベルに入れます。これはメソッドでデクリメントされます(engは申し訳ありません)

サンプル:

    sub MyAdd(i as integer)
      if i > 1 then
        MyAdd = i + MyAdd(i-1)
      else
        MyAdd = 1
      end if
    end sub
于 2012-05-21T21:42:14.503 に答える