出産前後の痔にはご注意!

昔、VBAで多次元配列のクイックソートの昇順版を作ったんですが、これの降順版を作成したいと思っているんですが、うまくいきません。どなたか正解を教えて下さい。

pMyLng の1つ目の添字のkeyNum 目の変数を昇順に並び替えるマクロです。


こんな感じで使っています。


ReDim xxx(1 To 2, 1 to 3)
xxx(1,1)="海"
xxx(1,2)="山"
xxx(1,3)="川"
xxx(2,1)=2
xxx(2,2)=1
xxx(2,3)=3
Call DoQuickSortHorizontalMulti(xxx, 2, UBound(xxx, 1), LBound(xxx, 2), UBound(xxx, 2))

Public Sub DoQuickSortHorizontalMulti(ByRef pMyLng As Variant, ByVal keyNum As Long, ByVal xLngMax As Long, ByVal pLngMin As Long, ByVal pLngMax As Long)
Dim i As Long
Dim j As Long
Dim k As Long
Dim BaseNum As Long
Dim BaseVal() As Variant
Dim Buf() As Variant
ReDim BaseVal(1 To xLngMax)
ReDim Buf(1 To xLngMax)
If pLngMin >= pLngMax Then
Exit Sub
Else
BaseNum = (pLngMin + pLngMax) \ 2
For k = 1 To xLngMax
BaseVal(k) = pMyLng(k, BaseNum)
Next k
For k = 1 To xLngMax
pMyLng(k, BaseNum) = pMyLng(k, pLngMin)
Next k
i = pLngMin
For j = pLngMin + 1 To pLngMax
If pMyLng(keyNum, j) < BaseVal(keyNum) Then
i = i + 1
For k = 1 To xLngMax
Buf(k) = pMyLng(k, i)
Next k
For k = 1 To xLngMax
pMyLng(k, i) = pMyLng(k, j)
pMyLng(k, j) = Buf(k)
Next k
End If
Next
For k = 1 To xLngMax
pMyLng(k, pLngMin) = pMyLng(k, i)
pMyLng(k, i) = BaseVal(k)
Next k
Call DoQuickSortHorizontalMulti(pMyLng, keyNum, xLngMax, pLngMin, i - 1)
Call DoQuickSortHorizontalMulti(pMyLng, keyNum, xLngMax, i + 1, pLngMax)
End If
End Sub

A 回答 (1件)

詳細は見ていませんが、大小関係を反転すれば良いので


If pMyLng(keyNum, j) < BaseVal(keyNum) Then

If pMyLng(keyNum, j) >= BaseVal(keyNum) Then

にしてみてはいかがでしょうか。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

Q多次元配列のソート方法

下記のような配列があったとして、
(1)科目名で昇順ソート
(2)氏名で昇順ソート
を行うにはどのように記述すればいいでしょうか?
よろしくお願いいたします。

Dim results(2, 3) As String
results(0, 0) = "国語"
results(1, 0) = "武田"
results(2, 0) = "90点"

results(0, 1) = "英語"
results(1, 1) = "藤田"
results(2, 1) = "32点"

results(0, 2) = "国語"
results(1, 2) = "坂上"
results(2, 2) = "45点"

results(0, 3) = "英語"
results(1, 3) = "浅木"
results(2, 3) = "12点"

下記のような配列があったとして、
(1)科目名で昇順ソート
(2)氏名で昇順ソート
を行うにはどのように記述すればいいでしょうか?
よろしくお願いいたします。

Dim results(2, 3) As String
results(0, 0) = "国語"
results(1, 0) = "武田"
results(2, 0) = "90点"

results(0, 1) = "英語"
results(1, 1) = "藤田"
results(2, 1) = "32点"

results(0, 2) = "国語"
results(1, 2) = "坂上"
results(2, 2) = ...続きを読む

Aベストアンサー

画像を見た感じだと、
> Dim results(2, 3) As String

――というデータ構造を採用した時点で、いけてないような。
Type Result_T: Seito As String: kamoku As String: ten As Integer: End Type
みたいなユーザ定義型を作って処理したほうがよいかと。

ADOとか使ってよいなら、ADODB.Recordsetに突っ込めばソートも一発でできそうな。

どうしても絶対にresults(2, 3)を使わなきゃいけないのだとしたら、比較後のデータ交換時にその配列間でデータを入れ替えればよいだけかと。

どういうアプローチを取ってよいか問題の出題範囲を確認してみては。

Q別のシートから値を取得するとき

Worksheets("シート名").Activate
上記のを行ってから別シートの値を取得するのですが、
この処理を行うと指定したシートへ強制的にとんでしまいます。。。

※イメージ
For ~ To ~
  Worksheets("シートA").Activate
  シートAの値取得
       :
  Worksheets("シートB").Activate
  シートBの値取得
Next

このイメージ処理を行うとものすごい勢いで画面がチカチカします。。。
シートを変えずに他のシートから値を取得する方法はないのでしょうか。
教えてください!

Aベストアンサー

Worksheets("シートA").Range("A1")

みたいな感じでできませんか?

QRange("A1")⇔cells(1,1)の変換。

EXCELのマクロについて質問します。
Range("A1")⇒(1,1)
cells(1,1)⇒("A1")
に一発変換する方法を教えて下さい。
時間があるかた宜しくお願いします。

Aベストアンサー

こんなのでよろしいでしょうか?
range("A1") → Range("A1").Row & "," & Range("A1").Column
cells(1,1) → Cells(1, 1).Address(False, False)
()や""は付けていません

QEXCEL VBAで、PasteSpecialと Destinationの組み合わせ方法?

ここで教えていただいたマクロで

ActiveSheet.Paste Destination:=Workbooks(\"book1.xls\").Worksheets(\"Sheet1\").Range(\"A1\")

のペースト部分を書式を除きたいので

PasteSpecial Paste:=xlFormulas

でやりたいのですが、どう組み合わせたらいいのかわかりませんでした。
おしえていただけませんでしょうか?

Aベストアンサー

moooonさん、こんにちは。
結論から言うと、
ActiveSheet.Paste Destinationと、PasteSpecialの組合せはできないようです。
(下記URL参照)
なので、前回ご紹介したマクロの
Worksheets("AAA").UsedRange.Copy
の後を
ActiveSheet.Paste Destination:=Workbooks(\"book1.xls\").Worksheets(\"Sheet1\").Range(\"A1\")
ではなく、
maruru01さんのご回答のように書き換える必要があると思います。
Destinationの場合は、クリップボードを経由せずに直接
コピーペーストできる、というものですが、
書式を除く等の作業が伴うと、クリップボードを経由させる必要があるようです。

参考URL:http://www.asahi-net.or.jp/~zn3y-ngi/YNxv998.html

QVBAでループ内で使う変数名を可変にできないか。

次のような処理で・・・、
 Cnt_1 = Cnt_1 + 1
 Cnt_2 = Cnt_2 + 1
   :
実際には一つの変数(Cnt_1など)ごとに処理がもっとあるのですが、
変数はCnt_1からCnt_5まであり、すべて同じ処理をするので、変数名を
可変にして同じループで書けないかと思うのですが、可能でしょうか?

たとえば、
For I=1 to 5
 Cnt_I = Cnt_I + 1
Next I
と書くと、「Cnt_I」という変数の処理になってしまいますね・・。

なにかいい方法はないでしょうか?

Aベストアンサー

こんばんは。

配列変数を使えばいいでしょう。
変数を5個用意して、すべて1~5まで足すという処理の場合です。
Dim Cnt(4) As Integer
Dim i As Integer
Dim j As Integer
For i = 0 To 4
For j = 1 To 5
Cnt(i) = Cnt(i) + j
Next j
Next i
どうでしょうか。

Q文字列をソートする方法

数値をソートする方法にはバブルソートやクイックソートなどがあり
アルゴリズムは分かるのですが
文字列を五十音順にソートしたい場合にはどのようにしたら良いですか?


検索をかけてみたのですが、大抵プログラミング言語に備わったsortの方法が紹介されており
自分で処理を行う方法については書かれていません。


ExcelのSort機能を使わない方法で教えてください。

Aベストアンサー

例えばバブルソートは
for j=0 to AMax
 for i=1 to AMax-j
  if A(i-1)>A(i) then
   入れ替え
  end if
 next
next
大体こんな感じですよね。
ここでは、大小比較に「>」を使っています。

ここで 「比較」 という関数を定義したとします。
比較(x,y) :
x が yより「大きい」ときは 正の値、「等しい」なら0、 「小さい」なら負の値を返す
これを使うと
for j=0 to AMax
 for i=1 to AMax-j
  if 比較(A(i-1),A(i)) > 0 then
   入れ替え
  end if
 next
next
と書けます。

さて
「大きい」「等しい」「小さい」
と「」付きで書いたのには理由があります。
後ろにくるべきものを「大きい」前にくるべきものを「小さい」と判定するように作れば、実は、実際の数値の大小以外にも使えるのです。
例えば 、x>y のとき 負、x<yのとき正 として作れば 実際には数の小さい方が「大きい」というということになり、その結果、逆順にソートされます。

この比較関数を使った方法は、他のアルゴリズムでも同様です。



> 文字列を五十音順にソートしたい場合

五十音順並べた時の大小関係を返す比較関数を用意しましょう。
いわゆる「辞書順」というのは
(1) 1文字目同士比較する。
(2) 違いがあれば、(1)の比較結果が文字列同士の比較結果
(2-1) もし、どちらか一方だけが文字が無い場合は、短い方が「小さい」
(2-2) 両方との文字が無くなったら、「等しい」
(3) 2文字目、3文字目...について(1)から同様に確認
というアルゴリズムになっています。



一応、文字列も 不等号で比較できますし、 StrCompという文字列比較関数もあります。
これらで間に合うようなら、使えばいいでしょう。
それで期待通りにならない場合は、比較関数を自作してみましょう。

例えばバブルソートは
for j=0 to AMax
 for i=1 to AMax-j
  if A(i-1)>A(i) then
   入れ替え
  end if
 next
next
大体こんな感じですよね。
ここでは、大小比較に「>」を使っています。

ここで 「比較」 という関数を定義したとします。
比較(x,y) :
x が yより「大きい」ときは 正の値、「等しい」なら0、 「小さい」なら負の値を返す
これを使うと
for j=0 to AMax
 for i=1 to AMax-j
  if 比較(A(i-1),A(i)) > 0 then
   入れ替え
  end if
 next
next
と書けます。

さて
「大きい」...続きを読む

Q「インスタンス」の意味をわかりやすく教えてください

VBのヘルプなどによく出てくる「インスタンス」という言葉の意味をもっとわかりやすく教えてください。

Aベストアンサー

もっと噛み砕いちゃいましょう。

例えばMac/VというパソコンをGrapeという会社が発売するとしましょう。
Grape社が用意する仕様に従って、製品が出来上がるわけですが、私が買ったMac/Vとあなたの買ったMac/Vは全く同じ仕様ですが、別々に存在するので全く同じ物では有りません。

というお話の中の「仕様」がクラスで、「私のMac/V」や「あなたのMac/V」がインスタンスです。

Q2次元配列の初期値

こんにちは
VBで2次元配列に初期値をまとめて入れる方法がわからなくて困っています。
簡単なはずなのにわかりません。
教えてくれるようお願いします。

Aベストアンサー

田吾作7です。

あぁーすいません。
初期化だと思ってて、勘違いしてました。すいません。。。
初期化ではなく、初期値のセットですね。。。

Variant型でもよければ
  dim wkAryas Variant'バリアント宣言
  wkAry = Array(Array(10, 100, 42, 90), Array(50, 30, 60, 30))
といった形でできます。



もし何度も同じ初期値をセットする必要があるのであれば、メモリコピーをお勧めします。
それが一番リソースを消費しない方法だと思います。
以下にソースを記します。
手順1.二次元配列の初期値のマスタを作成(CreAryMst)
手順2.ワークの二次元配列に初期値をセット(InitAry)
手順3.ワークを使用したロジックの実行(ユーザの処理)
手順4以降は手順2または手順3の処理の繰り返し

Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private mstAry(1, 3)  As Long '二次元配列の初期値のマスタ
Private matrixCount   As Long '配列要素数

Sub Main()
  Dim wkAry(1, 3)   As Long '実際に操作する二次元配列
  
  '二次元配列の初期値マスタを創生
  Call CreAryMst
  
  '変数に初期値をセットする
  Call InitAry(wkAry(0, 0))
  
End Sub

'二次元配列の初期値マスタを創生
Sub CreAryMst()
  Dim dmyAry As Variant
  Dim i    As Long
  Dim j    As Long
  
  Dim min1  As Long
  Dim max1  As Long
  Dim min2  As Long
  Dim max2  As Long
  
  min1 = LBound(mstAry, 1)
  max1 = UBound(mstAry, 1)
  min2 = LBound(mstAry, 2)
  max2 = UBound(mstAry, 2)
  
  '配列要素数を取得
  matrixCount = (max1 - min1 + 1) * (max2 - min2 + 1)
  
  '初期値をダミー変数にセット
  dmyAry = Array(CLng(10), CLng(50), CLng(100), CLng(30), CLng(42), CLng(60), CLng(90), CLng(30))
  
  '初期値をセットする
  For i = min1 To max1
    For j = min2 To max2
      mstAry(i, j) = dmyAry(i * max2 + j)
    Next j
  Next i
End Sub

'変数に初期値をセット
Sub InitAry(inLngAryTop As Long)
  Call CopyMemory(inLngAryTop, ByVal VarPtr(mstAry(0, 0)), ByVal LenB(inLngAryTop) * matrixCount)
End Sub




こうすることにより、初期値のセットが一瞬で済むので、初期値セット毎にかかる負荷が抑えることができます。

田吾作7です。

あぁーすいません。
初期化だと思ってて、勘違いしてました。すいません。。。
初期化ではなく、初期値のセットですね。。。

Variant型でもよければ
  dim wkAryas Variant'バリアント宣言
  wkAry = Array(Array(10, 100, 42, 90), Array(50, 30, 60, 30))
といった形でできます。



もし何度も同じ初期値をセットする必要があるのであれば、メモリコピーをお勧めします。
それが一番リソースを消費しない方法だと思います。
以下にソースを記します。
手順1.二次元配列...続きを読む

QSub ***( ) と Private Sub ***( ) の違い

初歩的な質問で申し訳ありませんが・・・

自分でコードを書いていても、イベントが発生したりした時の処理で、コードのウィンドウで上のドロップダウンリストで選択できる時の処理などは自動的に[Private Sub Command1_Click( )]などと出てくるのでそのまま使っています。自分で別途プロシージャーを作成する時は[Sub ****( )]としています。
ですがその違いを理解しないまま、自分で作成する時は[Private Sub]ではなくて[Sub]を使っています。

Sub ***( ) と Private Sub ***( ) の違いは何なんでしょうか?
どなたか説明頂けませんか?
よろしくお願いします。

Aベストアンサー

「Sub」の部分にカーソルを置いて[F1]を押せばヘルプが起動します。
「指定項目」のところに「Public」と「Private」の説明がありますよ。
省略して「Sub hogehoge()」とした場合は「Public」とみなされます。

Publicは「すべてのモジュールから呼び出せるプロシージャ」ということになります。
Privateとすると「同じモジュールの中からしか呼び出せないプロシージャ」となります。

もしExcelをお持ちでしたらExcelのVBEで標準モジュールを追加し、「Sub Test1()」と「Private Sub Test2()」を作成してみてください。
そしてExcelの[ツール]-[マクロ]-[マクロ(Alt+F8)]でマクロ実行のダイアログを表示させてみるとわかります。
ここには実行できるプロシージャの一覧が表示されますが、Test1は表示されているけれどTest2は表示されません。
Test1はPublicで、Test2はPrivateだからです。

QEXCEL_VBAでOracleにADO接続してSQL文で追加/更新したい

EXCELで入力した値をADO接続して
SQL文で登録したいのですが 誰かサンプルソース
作成していただけないでしょうか?

Aベストアンサー

手抜きのような気もしますが…
Oracle OLACLEDBデータベースのSCOTTスキーマに「テスト」テーブルがある物とします。
NAME VARCHAR2
KOE VARCHAR2

Excelでは、ツール-参照設定で"Microsoft ActiveX Data Objects 2.0 Library"を参照します。

Module1を作成して、
↓ここから
Option Explicit

' ADOのオブジェクト変数を宣言
Private cnn As New ADODB.Connection
Private cmd As New ADODB.Command

Private Sub sTest()
On Error GoTo err_hdr
' Oracleの接続
cnn.Open "Provider=MSDAORA;" & _
"Data Source=ORACLEDB;", "SCOTT", "TIGER"
Set cmd.ActiveConnection = cnn
'追加の例
With cmd
.CommandText = "INSERT INTO テスト" _
& " (NAME , KOE)" _
& " VALUES ( '" & "ねこ" & "'" _
& " , '" & "にゃん" & "')"
.CommandType = adCmdUnknown
.Execute
End With
'更新の例
With cmd
.CommandText = "UPDATE テスト" _
& " SET テスト.NAME='" & "ねこ" & "'" _
& " , テスト.KOE='" & "にゃお~ん" & "'" _
& " WHERE " _
& " テスト.NAME='" & "ねこ" & "'" _
& " AND テスト.KOE='" & "にゃん" & "'"
.CommandType = adCmdUnknown
.Execute
End With
'削除の例
With cmd
.CommandText = "DELETE FROM テスト" _
& " WHERE " _
& " テスト.NAME='" & "ねこ" & "'" _
& " AND テスト.KOE='" & "にゃお~ん" & "'"
.CommandType = adCmdUnknown
.Execute
End With

cnn.Close

Set cmd = Nothing
Set cnn = Nothing
Exit Sub
err_hdr:
Resume Next
End Sub
↑ここまで

「ねこ」とかの代わりにExcelシート上のセルからデータを取得して
セットするように改造下さればなんとかなるかと思います。

手抜きのような気もしますが…
Oracle OLACLEDBデータベースのSCOTTスキーマに「テスト」テーブルがある物とします。
NAME VARCHAR2
KOE VARCHAR2

Excelでは、ツール-参照設定で"Microsoft ActiveX Data Objects 2.0 Library"を参照します。

Module1を作成して、
↓ここから
Option Explicit

' ADOのオブジェクト変数を宣言
Private cnn As New ADODB.Connection
Private cmd As New ADODB.Command

Private Sub sTest()
On Error GoTo err_hdr
' Oracleの接続
cnn.Open "Provider=M...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング