私が持っているもの:
n = 5
0, 0, 0, 0, 1000, 0, 0, 0, 0
私が欲しいもの:
0, 0, 0, 0, 200, 200, 200, 200, 200, 0, 0...
つまり、上の行に値(1000)が表示された場合、下の行には均等にその価値を分割するんすべての分割の合計が元の値と等しくなるまで繰り返します。
可能であれば、VB の使用は避けたいと思います。
編集1:
遭遇するあらゆる値が n で割り切れるという保証はありますか?
いいえ。ただし、合計値と元の値の差が 1 未満になったら、続行します。
n 回の分割に十分なセルがあることが保証されていますか?
いいえ。
ゼロ以外の値が 1 つだけあることが保証されていますか?
いいえ、複数の値があります。上の行に別の値が表示され、下の行の分割が完了していない場合、下の行では古い分割と新しい分割が合計されます。
ゼロ以外の値は常に同じ位置にありますか?
いいえ。最初の位置以外の任意の位置に出現できます。
編集2:
透明性を保つために、私は大きな費用を均等に分散させようとしていますん年。
おそらく、これはより良い例でしょう:
ご了承ください:
入力値を分割するプロセスは、それぞれの分割の合計が入力値と等しくなるまで実行する必要があります。
前の入力値の分割がまだ完了していないときに別の入力値が見つかった場合、出力行は、すべての入力値の最初のポイントの条件が満たされるまで、それぞれの分割を合計して続行されます。
答え1
編集:以前の不必要に複雑な式(この改訂) は依然として役に立ちますが、たとえば、入力にスライディング スケーリング係数を適用する必要がある場合は、この回答では、よりシンプルで理解しやすい新しいバージョンに置き換えました。
ヘルパー行/列や追加のテーブルを必要としない非 VBA ソリューションを次に示します。
{=SUM(IFERROR(INDEX($2:$2,N(IF(1,COLUMN()-(COLUMN(INDEX(3:3,1):INDEX(3:3,$A$5))-1))))/$A$5,0))}
説明:
式の簡略版は次のようになります。
{=
SUM(
IFERROR(
INDEX(
($2:$2),
N(IF(1,COLUMN()-(COLUMN(INDEX(3:3,1):INDEX(3:3,$A$5))-1)))
)/$A$5,
0
)
)}
INDEX()
n = 5 の場合、最初の引数の 2 番目の引数が実質的に次の引数と同等であることを考慮すると、式ははるかに理解しやすくなります。
COLUMN()-{0,1,2,3,4}
これは基本的に、可変長 (A5
私の例では格納されている n に基づく) のオフセット配列を生成して、前の n-1 と現在の入力値にアクセスすることによって機能します。
数式を順に実行すると、I3
上記の内容がより明確になります。
(COLUMN(INDEX(3:3,1):INDEX(3:3,$A$5))-1)
→{1,2,3,4,5}-1
→{0,1,2,3,4}
COLUMN()-{0,1,2,3,4}
→{9}-{0,1,2,3,4}
→{9,8,7,6,5}
N(IF(1,{9,8,7,6,5}))
→N({9,8,7,6,5})
→{9,8,7,6,5}
(INDEX($2:$2,{9,8,7,6,5})/$A$5
→{100000,0,0,0,7}/5
→{20000,0,0,0,1.4}
SUM(IFERROR({20000,0,0,0,1.4},0))
→20001.40
INDEX($2:$2,N(IF(1,expression)))
は、Excelに配列を返させるために必要なハックです。2expression
番目の引数はINDEX()
デフォルトで単一の値に評価されるためです。INDEX($2:$2,expression)
I3
INDEX($2:$2,COLUMN()-(COLUMN(INDEX(3:3,1):INDEX(3:3,$A$5))-1))
→ INDEX($2:$2,9-(COLUMN($A$3:$E$3)-1))
→ → →INDEX($2:$2,9-(1-1))
INDEX($2:$2,9)
100000
単一の値を返す式内では、範囲の最初のセルの列が返されます。COLUMN(multi-cell-range)
このIFERROR()
関数は、数式がシートの左側に近いセルに存在する場合に必要となり、その結果、行ヘッダーにアクセスするか、列の左側のセルにアクセスしようとすることになりますA
。
ノート:
- 整形された数式は、入力すると実際に機能します。
- 整形されたバージョンでは、 を独自の行に残すために括弧
($2:$2)
が必要です。$2:$2
*なぜハックが機能するのかという正確な説明は、まず私自身が理解するまで待たなければなりません ;-)
答え2
コード:
Sub Divide(n As Integer)
Dim temp(), i As Integer, j As Integer, cnt As Integer, tmp
' Copy values from row to array
temp = Rows(Selection.Row).Value
' Search for the last cell. Use SpecialCells instead is the better variant.
For i = UBound(temp, 2) To LBound(temp, 2) Step -1
If Not IsEmpty(temp(1, i)) Then
cnt = i
Exit For
End If
Next i
' Perform main operation
For i = cnt To 1 Step -1
If Rows(Selection.Row).Cells(1, i).Value <> 0 Then
tmp = Rows(Selection.Row).Cells(1, i).Value
Rows(Selection.Row).Cells(1, i).Delete Shift:=xlShiftToLeft
For j = 1 To n
Rows(Selection.Row).Cells(1, i).Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Rows(Selection.Row).Cells(1, i).Value = tmp / n
Next
End If
Next
End Sub
Sub は
n
値をパラメータとして受け入れます。サブは、選択範囲(左上隅)の行を処理します。
Sub は、セル内の値が比較および
0
除算のために数値に変換されるかn
どうかをチェックしません。他のエラーもチェックされません。
列制限を超えて移動した場合、シフトされた値は失われます。
そして最適化は全く行われていません。
このコードをアイデアとして使用します。
答え3
ここでは、VBA を使用する必要のない実用的なソリューションを示します。
唯一の違いは、各コストを個別に入力するためにどこかにテーブルを追加する必要があることです。
これを実行することを強くお勧めします。計算が大幅に簡素化され、財務面での明確さも大幅に向上します。コスト参照、説明、サーバーの種類などの列を簡単に追加できます。また、複数のアイテムがある場合は、数量と基本価格の列を追加することもできます。これを拡張して興味深いレポートを作成できます。私の意見では、VBA を書くよりもはるかに簡単です。
黄色のセルは入力を表します。
- C2では、他の場所から
_N
簡単に変数にアクセスできるようにセルに名前を付けます。5 years
- 費用(範囲)については、参照しやすいように
A5:D10
名前を付けられる表を挿入します。Costs
使用する数式は次のとおりです。必要に応じて、右にドラッグ/コピーします (スクリーンショットでは青色で示されています)。
=IFERROR([@[Real Cost]]/_N;0)
=IF([@From]>0,[@From]+_N-1,"")
=SUMPRODUCT((B$13=Costs[From])*(Costs[Real Cost]))
=SUMPRODUCT((B$13>=Costs[From])*(B$13<=Costs[Until])*(Costs[Yearly Cost]))