数値変数の値を別の変数を使わずに入れ替える
ツイッターで出したエクセルVBAのお題です。
問題を出したツイート
変数a,b,cに整数値が入っています。
これをa>b>cとなるように値を入れ替えてください。
ただし、変数(プロパティ含む)の使用は不可、変数を使用せずに値を入れ替えてください。
(関数戻り値の無名は使ってよい)
なお、a,b,cのデータ型は随意。
https://twitter.com/yamaoka_ss/status/1315298046880620544
Sub test()
Dim a, b, c
a = 5
b = 9
c = 7
Call fnc(a, b, c)
Debug.Print a, b, c '→9,7,5
End Sub
Function fnc(a, b, c)
'ここで変数を宣言せずに値を入れ替える
End Function
ツイートした後に、あー、と思ったのですが、、、
そういう事に気づくかどうも含めて、ツイートならではのお題としては良いのかもしれないと思い、そのままにしました。
お寄せいただいた回答
一つずつ紹介したいのですが数が多くて紹介しきれなくなってしまいました。
頂いた回答は、こちらの検索結果からご覧ください。
・配列に入れてシート関数を使う
・独創的な方法(再帰含む) :上記2通りの応用です。
用意した解答
例として関数fncと書いてしまったので、このfncを使えば簡単に入れ替えできてしまいます。
fncに値を入れられるので、1つ余分に変数があるようなものなので簡単に入れ替えられます。
それはそれで、そこに気づいたということで回答として良いと思います。
さすがに、以下はこの方法を除いた解答になります。
例えば、
f(x,y) = z
このとき、zとy(またはx)を使って逆算できる場合、
f'(z,y) = x
f'(z,x) = y
これが一意の値として求められるような演算fとf'があるなら、zがあればxまたはyの片方は無くても良いという事になりす。
簡単に例示します。
このとき、7と12があればいつでも5は求めることができます。
12 - 7 = 5
a,bで書くと、
a + b = z
このとき、bとzがあればaはいつでも求められます。
そこで、VBAで、
a = a + b ・・・ ①
この時点で、(a + b)とbの値が手元にあります。
これでいつでもaは求めることができます。
b = a - b ・・・ ②
aの値は元の(a + b)なので、上の式の結果は元のaになります。
a = a - b ・・・ ③
aの値は元の(a + b)、bの値は元のaの値なので、この式の結果は元のbの値になります。
①②③の結果、a,bの値は入れ替わります。
これを使ってVBAでa,b,cを入れ替えます。
Function fnc(a, b, c)
If a < b Then
a = a + b
b = a - b
a = a - b
End If
If a < c Then
a = a + c
c = a - c
a = a - c
End If
If b < c Then
b = b + c
c = b - c
b = b - c
End If
End Function
a,b,cの3値なので、3通りの比較が必要になります。
ここでは+と-でやりましたが正確に逆算できるならどんな演算子でも構わないという事になります。
といってもVBAに用意されている演算子は限られていますが。
※一意に逆算できるのなら、独自の関数でやっても構いません。
詳細まで説明しきれませんが、概要だけ。
Xorはビット演算で、どちらか片方だけが1の時のみ1になります。
0101 Xor 0111 = 0010
5 | 0 | 1 | 0 | 1 |
7 | 0 | 1 | 1 | 1 |
2 | 0 | 0 | 1 | 0 |
2 Xor 7 = 5
0010 Xor 0111 = 0101
2 | 0 | 0 | 1 | 0 |
7 | 0 | 1 | 1 | 1 |
5 | 0 | 1 | 0 | 1 |
2 Xor 5 = 7
0010 Xor 0101 = 0111
2 | 0 | 0 | 1 | 0 |
5 | 0 | 1 | 0 | 1 |
7 | 0 | 1 | 1 | 1 |
このように2値のXorの結果と元の片方の値のXorをとると、もう片方の値を求めることができます。
つまり逆算ができるという事です。
これを使ってVBAでa,b,cを入れ替えます。
Function fnc(a, b, c)
If a < b Then
a = a Xor b
b = a Xor b
a = a Xor b
End If
If a < c Then
a = a Xor c
c = a Xor c
a = a Xor c
End If
If b < c Then
b = b Xor c
c = b Xor c
b = b Xor c
End If
End Function
それではつまらないですよね(笑)
以下は、エクセルVBAならではのやり方になります。
3値が配列に入っているので、
後は大きい順(もしくは小さい順)に取り出せば良いことになります。
まずは、1つずつ比較して取り出してみます。
Function fnc3(a, b, c)
a = Array(a, b, c)
Select Case True
'a(0)<a(1),a(2)
Case a(0) < a(1) And a(0) < a(2)
If a(1) < a(2) Then
c = a(0): b = a(1): a = a(2)
Else
c = a(0): b = a(2): a = a(1)
End If
'a(1)<a(0),a(0)
Case a(1) < a(0) And a(1) < a(2)
If a(0) < a(2) Then
c = a(1): b = a(0): a = a(2)
Else
c = a(1): b = a(2): a = a(0)
End If
'a(2)<a(0),a(1)
Case a(2) < a(0) And a(2) < a(1)
If a(0) < a(1) Then
c = a(2): b = a(0): a = a(1)
Else
c = a(2): b = a(1): a = a(0)
End If
End Select
End Function
うーん、マルチステートメントを使ってもなお長いですね。
エクセルには便利な関数が多数あります。
Function fnc(a, b, c)
a = Array(a, b, c)
c = WorksheetFunction.Small(a, 1)
b = WorksheetFunction.Small(a, 2)
a = WorksheetFunction.Small(a, 3)
End Function
上記ではSmall関数を使っていますが、配列を変数cに入れてLarge関数を使っても同じです。
また3値だけなので、Max関数とMin関数を使った方法もあるでしょう。
Function fnc(a, b, c)
a = WorksheetFunction.Sort(Array(a, b, c), , 1, True)
c = a(LBound(a))
b = a(LBound(a) + 1)
a = a(LBound(a) + 2)
End Function
Array関数は横の1次元配列なので、4番目の引数で列方向を指定しています。
TransposeeしてからSortしても良いですが、その場合は2次元配列になるので気を付けてください。
お寄せいただいた回答では、さらに様々な方法で取り組まれていますので、ぜひ参考に読んでみてください。
同じテーマ「ツイッター出題回答 」の記事
配列のUBoundがLBoundがより小さいことはあり得るか
コレクションの要素を削除する場合
greeenはgreenに、greeeeeNをGReeeeNに変換
数値変数の値を別の変数を使わずに入れ替える
Rangeオブジェクトを受け取り"行数,列数"で埋める
数式の関数の使用回数、関数名を配列で返す
日付型と通貨型のValueとValue2について
小文字"abc"を大文字"ABC"に変換する方法
オブジェクトのByRef、ByVal、Variant
「マクロの登録」で登録できないプロシージャーは?
ジャグ配列から順列を作成する
新着記事NEW ・・・新着記事一覧を見る
TRIMRANGE関数(セル範囲をトリム:端の空白セルを除外)|エクセル入門(2024-08-30)
正規表現関数(REGEXTEST,REGEXREPLACE,REGEXEXTRACT)|エクセル入門(2024-07-02)
エクセルが起動しない、Excelが立ち上がらない|エクセル雑感(2024-04-11)
ブール型(Boolean)のis変数・フラグについて|VBA技術解説(2024-04-05)
テキストの内容によって図形を削除する|VBA技術解説(2024-04-02)
ExcelマクロVBA入門目次|エクセルの神髄(2024-03-20)
VBA10大躓きポイント(初心者が躓きやすいポイント)|VBA技術解説(2024-03-05)
テンキーのスクリーンキーボード作成|ユーザーフォーム入門(2024-02-26)
無効な前方参照か、コンパイルされていない種類への参照です。|エクセル雑感(2024-02-17)
初級脱出10問パック|VBA練習問題(2024-01-24)
アクセスランキング ・・・ ランキング一覧を見る
1.最終行の取得(End,Rows.Count)|VBA入門
2.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.RangeとCellsの使い方|VBA入門
6.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.条件分岐(Select Case)|VBA入門
10.ブック・シートの選択(Select,Activate)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。