• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:VBAで最大値と2番目の取得方法)

VBAで最大値と2番目の取得方法

このQ&Aのポイント
  • ExcelのVBAで行ごとに最大値と2番目の値を取得する方法について解説します。
  • 最大値と2番目の値を取得する際には、項目名も一緒に取得することができます。
  • 取得数の上限が2件の場合、優先順位の表にしたがって上位2件を取得します。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

こんにちは。 この表を見ていて気がついたことですが、#1さんがご指摘の、 「優先順位を考慮した成績表を別に作った方が良さそうに思えます。」 同感です。あえて、それを、プログラム上で行うとすれば、配列変数(myIndex )の中でしかありません。むろん、Excelなら、ダミーの表を作ってもよいかもしれません。一応、既存のユーザーの表自体を動かしてはいけない、という暗黙のルールには従いましたが…。VBAでは、ややこしくなるようです。 #1さんの回答にように、これは、関数でもできるような気がしますね。私自身は、関数が不得意なので、選択肢はありませんでしたが。 '// Sub OrderAsRequest()  Dim Rng As Range  Dim Rng2 As Range  Dim myIndex As Variant  Dim i As Long, j As Long, k As Long  Dim n As Variant  Dim mySubject As Variant  Dim max1 As Long, max2 As Long  Dim subj1 As String, subj2 As String    '出力先用  Dim ws As Worksheet  Dim m As Long  Set ws = Worksheets(2) '#4さんと同等にしました。  m = 1    Set Rng = Range("A1:F4") 'テスト成績表  Set Rng2 = Range("A7:B11") '優先順位  With Rng   Set Rng = .Offset(0, 1).Resize(.Rows.Count, .Columns.Count - 1)  End With  ReDim mySubject(Rng2.Rows.Count - 1)  ReDim myIndex(Rng.Rows.Count - 2, Rng.Columns.Count)  For i = 1 To Rng2.Rows.Count   mySubject(i - 1) = Rng2.Cells(i, 2).Value  Next i    'Rng2のフォーマットに従い優先順位に並べ替え    For i = 2 To Rng.Rows.Count   myIndex(i - 2, 0) = Rng.Cells(i, 1).Offset(, -1).Value '人名  F   For j = LBound(mySubject) To UBound(mySubject)    n = Application.Match(mySubject(j), Rng.Rows(1), 0)    myIndex(i - 2, j + 1) = Rng.Cells(i, n).Value   Next j  Next i  k = 2    '検索  For i = LBound(myIndex) To UBound(myIndex)   For j = LBound(myIndex, 2) + 1 To UBound(myIndex, 2)    If myIndex(i, j) > max1 Then     max1 = myIndex(i, j)     subj1 = mySubject(j - 1)    End If   Next j   '注意:出力先1   With ws    .Cells(m, 1).Value = myIndex(i, 0)    .Cells(m, 2).Value = subj1    .Cells(m, 3).Value = max1   End With      '二番目を調べる   For j = LBound(myIndex, 2) + 1 To UBound(myIndex, 2)    If mySubject(j - 1) <> subj1 Then     If myIndex(i, j) > max2 Then      max2 = myIndex(i, j)      subj2 = mySubject(j - 1)     End If    End If   Next j   '注意:出力先2   With ws    .Cells(m, 4).Value = subj2    .Cells(m, 5).Value = max2   End With   k = k + 1   m = m + 1   max1 = 0: max2 = 0: subj1 = "": subj2 = ""  Next i End Sub '//

その他の回答 (5)

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.6

No.4です。 前回のコードではエラーになりマクロが止まってしまいます。 最後から5行目の >wS.Range(Columns(3), Columns(lastCol)).Delete を >Range(wS.Columns(3), wS.Columns(lastCol)).Delete に変更してください。 どうも失礼しました。m(_ _)m

komegu_66
質問者

お礼

ありがとうございます。できました! その前にいただいたマクロでも止まることなく動きましたよ!

  • tom04
  • ベストアンサー率49% (2537/5117)
回答No.4

こんばんは! 一例です。 Sheet1のデータをSheet2のA・B列に表示するようにしてみました。 元データの1行目は項目で、データはA2セル以降にあるとします。 標準モジュールです。 Sub Sample1() Dim i As Long, k As Long, lastCol As Long Dim c As Range, r As Range, myRng As Range, wS As Worksheet, myBst, mySnd, myAry myAry = Array("国語", "英語", "社会", "数学", "理科") '←優先順位★ Set wS = Worksheets("Sheet2") wS.Cells.Clear '▼ Sheet2、C1セル以降に科目を優先順位順に表示(作業用として並び替え) For k = 0 To UBound(myAry) wS.Cells(1, k + 3) = myAry(k) Next k lastCol = wS.Cells(1, Columns.Count).End(xlToLeft).Column With Worksheets("Sheet1") '▼ Sheet2のC列以降の科目順に検索し、同じ数値がない場合のみその科目の数値を表示 For i = 2 To .Cells(Rows.Count, "A").End(xlUp).Row For k = 3 To lastCol Set c = .Rows(1).Find(what:=wS.Cells(1, k), LookIn:=xlValues, lookat:=xlWhole) If WorksheetFunction.CountIf(wS.Rows(i), .Cells(i, c.Column)) = 0 Then wS.Cells(i, k) = .Cells(i, c.Column) End If Next k '▼ Sheet2のC列~最終列を「myRng」に格納 Set myRng = Range(wS.Cells(i, "B"), wS.Cells(i, lastCol)) '▼ myRng範囲の最大値と2番目の値を取得 myBst = WorksheetFunction.Max(myRng) Set c = wS.Rows(i).Find(what:=myBst, LookIn:=xlValues, lookat:=xlWhole) '▼ 万一すべての科目が同点の場合の処理 If WorksheetFunction.Count(myRng) > 1 Then mySnd = WorksheetFunction.Large(myRng, 2) End If Set r = wS.Rows(i).Find(what:=mySnd, LookIn:=xlValues, lookat:=xlWhole) '▼ Sheet2のA列にSheet1のA列データを、B列に最大値の科目:点数、2番目の科目:点数 を表示 wS.Cells(i, "A") = .Cells(i, "A") If Not r Is Nothing Then wS.Cells(i, "B") = wS.Cells(1, c.Column) & ":" & myBst & "、" & wS.Cells(1, r.Column) & ":" & mySnd Else wS.Cells(i, "B") = wS.Cells(1, c.Column) & ":" & myBst End If Next i wS.Range(Columns(3), Columns(lastCol)).Delete wS.Columns.AutoFit wS.Range("A2").CurrentRegion.Borders.LineStyle = xlContinuous End With End Sub ※ 現実問題としてあるかどうかは判りませんが、 すべての科目が同点の場合は1科目(最優先)しか表示されません。m(_ _)m

  • weboner
  • ベストアンサー率45% (111/244)
回答No.3

>・Cさん: >・2番目→数学と理科の60?? 国語と英語の80であれば、数学と理科の60は2番目じゃなくて3番目なんじゃ?

  • mt2008
  • ベストアンサー率52% (885/1701)
回答No.2

ANo.1です。 ごめんなさい、VBAでの解決ですね。 先ほどの回答は忘れて下さい。

  • mt2008
  • ベストアンサー率52% (885/1701)
回答No.1

「何番目に大きい」を取り出す時はLARGE関数を使用します。 また、今回の内容ですと、優先順位を考慮した成績表を別に作った方が良さそうに思えます。 添付の図ではA13:F16を優先順位を考慮した成績表として使っています。 B14に↓を入れてB14:F16にコピーしています。 =B2-MATCH(B$13,$B$7:$B$11,0)/100 次にH2とI2には以下の式を入れます。 H2セル:=INDEX($B$1:$F$1,0,MATCH(LARGE($B14:$F14,1),$B14:$F14,0)) I2セル:=INDEX($B$1:$F$1,0,MATCH(LARGE($B14:$F14,2),$B14:$F14,0)) H2:I2を下2つにもコピーします。 こんな感じで如何でしょう。

komegu_66
質問者

お礼

ありがとうございます。できました! 当初VBAの予定でしたが、いただいた内容で作業シートとして 持てればその方が簡単かな。とも思い、ただいま検討中です。

komegu_66
質問者

補足

webonerさんからご指摘いただきました。ありがとうございます。 Cさんについては、ご指摘の通り以下になります。 ・Cさん:    ・最大値→国語と英語の80     優先順位で国語が上位にあるため、国語を取得。    ・2番目→英語を取得。 >・Cさん: >・2番目→数学と理科の60?? 国語と英語の80であれば、数学と理科の60は2番目じゃなくて3番目なんじゃ? >・Cさん: >・2番目→数学と理科の60?? 国語と英語の80であれば、数学と理科の60は2番目じゃなくて3番目なんじゃ?

関連するQ&A