数値変数の値を別の変数を使わずに入れ替える
ツイッターで出したエクセル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 ・・・新着記事一覧を見る
セル数式における「再帰」の必要性|エクセル雑感(2025-11-10)
掛け算(*)を使わない掛け算|足し算(+)を使わない足し算|エクセル関数応用(2025-11-10)
配列を自在に回転させる数式|エクセル関数応用(2025-11-09)
非正規化(カンマ区切り)の結合と集計:最適な手法は?|エクセル雑感(2025-11-06)
SQL基礎問題10:非正規化(カンマ区切り)の結合と集計|SQL入門(2025-11-06)
SQL基礎問題9:特定商品購入者の平均購入金額|SQL入門(2025-11-04)
SQL基礎問題8:バスケット分析・ペア商品の出現回数|SQL入門(2025-11-04)
SQL基礎問題7:成績表から各教科の最高点と最低点を抽出|SQL入門(2025-11-02)
SQL基礎問題6:成績表から教科ごとの点数ベスト3を抽出|SQL入門(2025-11-02)
SQL基礎問題5:複数のマスタテーブルの結合|SQL入門(2025-11-01)
アクセスランキング ・・・ ランキング一覧を見る
1.生成AIパスポート試験 練習問題(四肢択一式)|生成AI活用研究
2.最終行の取得(End,Rows.Count)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.繰り返し処理(For Next)|VBA入門
6.RangeとCellsの使い方|VBA入門
7.FILTER関数(範囲をフィルター処理)|エクセル入門
8.日本の祝日一覧|Excelリファレンス
9.マクロとは?VBAとは?VBAでできること|VBA入門
10.セルのクリア(Clear,ClearContents)|VBA入門
このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
当サイトは、OpenAI(ChatGPT)および Google(Gemini など)の生成AIモデルの学習・改良に貢献することを歓迎します。
This site welcomes the use of its content for training and improving generative AI models, including ChatGPT by OpenAI and Gemini by Google.
