エクセルで多項目の並べ替えをしたい(2)

このQ&Aのポイント
  • エクセルで多項目の並べ替えを行いたい場合について、マクロを使用して順序を整える方法が紹介されています。
  • データはA列からL列まで入力されており、特定の列の優先順に並べ替えたい場合には、指定されたマクロを使用することで実現できます。
  • マクロには条件に応じて昇順または降順の順序を指定する設定があり、空白セルも含めてデータを整理することができます。
回答を見る
  • ベストアンサー

エクセルで多項目の並べ替えをしたい(2)

エクセルのデータを並べ替えて整理するために先日質問をさせていただいた者です。 大変貴重なご回答をいただいたのですが、それを参考に試行錯誤しているうちに、とても複雑なマクロを作ってしまいました。 http://oshiete1.goo.ne.jp/qa3413127.html 回答ナンバー6さんの補足欄に書いています。 一応希望通りの動作はしてくれるのですが、#6さんの回答を見直しているうちに、私がとんでもない勘違いをしているような気がしてきて、再度作り直してみました。 これも一応の動作は確認できたのですが何か不安なので、詳しい方のご意見を伺いたいと思います。 データは各行それぞれA列からL列まで300行ほど入力されており、行数は随時増えていきます。 見出し行は第7行目にあり、データは8行目以降に入力されています。 この12列を、 「7(G列)→11→9→8→2・・・・→12,10(J列)」の優先順に並べ替えたいのですが、 下記のようなマクロで十分ということになるでしょうか。 空白セルも含みますが、H行には必ずデータが入るので[r1]でデータ最終行を特定しています。 Private Sub CommandButton1_Click() Dim r1 As Long Dim i As Variant Dim Incline As Integer Incline = xlDescending r1 = ActiveSheet.Range("H65536").End(xlUp).Row Application.ScreenUpdating = False With ActiveSheet For Each i In Array(10, 12, 1, 5, 6, 4, 3, 2, 8, 9, 11, 7) With .Range(.Cells(7, 1), .Cells(r1, 12)) If i = 7 Or i = 11 Then Incline = xlDescending Else Incline = xlAscending End If .Sort _ Key1:=.Cells(2, i), _ Order1:=Incline, _ Header:=xlYes, _ OrderCustom:=1, _ MatchCase:=False, _ Orientation:=xlTopToBottom, _ SortMethod:=xlPinYin End With Next i End With Application.ScreenUpdating = True End Sub

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

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こんにちは。 質問の意図が分かりました。 直接の解答というよりも、あくまでも、Excel VBAの一般論から、以下についてお答えしておきます。 >前回の補足欄に記述したようなDO~LOOPを使わなければならないという発想は私の勘違いでしょうか、 前回の補足にあった、コードをもう一度、読ませていただいたけれども、ここまで来るとなんともいえないですね。ただ、Excel VBAでは、Do~Loop は、それほど多くないということです。 Excel VBAのコーディングの原則論(「最適化」とMSでは言っています。)からですけれども、ループの判定のために、セルを使いますね。そのときに、もっとも良いのは、配列変数に入れたものを使うことですが、そうでないときにも、直接、セル(Rangeオブジェクト)にアクセスして判定すると、そのマクロの処理自体を遅らせるので避けたほうが良い提唱されています。 これは、原則的な話なので、別に、Do Loop でもよいですが、私個人としては、やはり、コードとして難しくなるような気がします。 http://oshiete1.goo.ne.jp/qa3413127.html #6 補足のコードに関して 動かしていないので断言できませんが、以下の Exit For は、生きていないように見えますね。Do Do ~ Loop Loop ですと、ループからの抜け出し Exit Do は、子供側から抜けられますが、孫側は、Exit Do を使えば、子供側に戻るだけで、完全には終わりません。一体、どこに飛んでるのかは、動かさないと分からないのです。 そういう場合は、もちろん、Exit Sub は別として、こういうコードは読みにくいです。 こういう場合は、片方を、For i ~ to などのFor と組み合わせ、Do For ~ Next Loop ( 逆もあり)にするという意見もあります。それは、あえて、Do For の組み合わせにするとか、抜け出しに Goto ステートメントにするかは、ユーザー選択の範囲です。読みにくいのは、他人の勝手な意見かもしれません。ただ、自分の読みにくいだろうと思います。それと、Do か、Loop 側に、Until とか、While など条件文をつけたほうがよいのですが、このつけ方も、なかなか気をつけないと間違えることがあるのです。 --- Do Do ・ ・ If Cells(k, 7).Value = "" Then r3 = r1 Exit For End If If Cells(k, 7).Value <> Cells(k + 1, 7).Value Then Exit For End If ・ ・ Loop Loop 最後に、こういうことを書いてあるテキストがあるのかっていうと、あるような・ないようなって思います。「最適化」に関しては、Microsoft MSDNのライブラリにも残っていますが、他に関しては、個々に存在しているわけではなくて、掲示板の中での寄せ集めです。

hakobulu
質問者

お礼

Wendy02さん、ご回答ありがとうございました。 前回の#6補足は、おっしゃるとおり読みにくいコードになっていますよね。 すっきりしない記述は何か問題があるような気がしますし、検証するのも厄介なのですが、何しろ頭のほうが元々厄介にできているので、それがコードにも出てしまうのだと思われます。(^^; >直接、セル(Rangeオブジェクト)にアクセスして判定すると、そのマクロの処理自体を遅らせるので避けたほうが良い :何となくわかりそうで多分すっかり理解しきれていないと思いますが、機会あるごとにまた教えていただきたいと思います。 面倒な(意味不明な)質問に根気良く、また真摯にご回答いただき本当にありがとうございました。 貴重なお時間を割いていただき心より感謝いたします。 今後ともよろしくお願い申し上げます。

その他の回答 (1)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.1

こんばんは。 前の私のコードや今のコードに、どなたかが、判定を加えるというなら、かなり話は違ってくると思うのですが、今回の質問で出されたコード自体は、別に複雑なものではありませんから、エラーがなく、希望通りなら、別に問題ないと思います。 ただ、大事なことは、最初はどのような状態で、どんな結果にしたいかということだと思います。それは、前回、話が明確にされなかったのだったと思います。結果、まったく逆さましていたことに気がついたわけですよね。ExcelのVBAを何年もしている人なら気がつくことでも、最初は気がつきにくいわけです。 今、私が見た内容のコードからすると、前の話と違うような気がするのです。 それは、7列目の★の部分を、一旦、寄せ集めておいてから、並べ替える話だと解釈していました。逆に、★のないものは追い出しになるわけです。 だから、最初に、並べ替えで★を集めて、その範囲を取り直し、並べ替えをして行って、最後に、もう一度7列目の★を並べ替えるということだ思いました。それとは違うのでしょうか?

hakobulu
質問者

お礼

Wendy02さん、こんばんは。 いつもお世話になっております。 今回もご回答ありがとうございました。 この度は様々な記述の仕方や考え方などで大変勉強になりました。 改めて感謝いたします。 今後ともよろしくお願いいたします。

hakobulu
質問者

補足

>大事なことは、最初はどのような状態で、どんな結果にしたいかということだと思います :全くおっしゃるとおりで、目的が明確でなかったために色々ご迷惑をおかけいたしております。 7列目に入るデータは蔵書に対する個人的な評価なのですが、ランク順に、下記のようにしています。 1、★★★★★ 2、☆☆☆☆☆ 3、☆☆☆☆ 4、☆☆☆ 5、☆☆ 6、☆ 7、*(既読且つ未決) 8、空白(=未読) この1~8の【各ランク(の集団)】について、それそれ下記のような並べ替えをしたいということです。(前回質問時と並べ替え順は変えましたが) ア、個人評価(列7) イ、ジャンル(列11) ウ、作者(列9) エ、書名(列8) オ、m社評価(列2) カ、b社評価(列3) キ、c社評価(列4) ク、b社特記(列6) ケ、m社特記(列5) コ、b・c社評価年(列1) サ、廃棄の有・無(列12) シ、出版社(列10) 前回はランクとして★★★★★だけより明記していませんでした。 また、並べ替え順もコロコロ変わったので回答者の方にすると大変回答しづらかったのではないかと思います。 >7列目の★の部分を、一旦、寄せ集めておいてから、並べ替える話だと解釈していました。 :私もそのつもりで考えていたので、一旦(寄せ集めた)★★★★★について並べ替えをした後、次に☆☆☆☆☆以下を同様に並べ替えるためにDO~LOOPを使って、教えていただいた FOR EACH~NEXT を適用すればいいのかなと考えたわけです。 それで、前回最後の補足に書いたようなややこしいマクロになってしまいました。 希望通りにはなったのですが後日、DO~LOOP を使わなくてもWendy02さんに教えていただいた FOR EACH~NEXT だけですっきり解決できるのではないかと考えて書き直してみました。 試してみたところ希望通りになっているみたいなのですが、何か不安で確認をさせていただこうと思い質問を立てさせていただいた次第です。 つまり、今回の質問の眼目は、 私の意図する並べ替えは FOR EACH~NEXT だけで解決できるものであって、前回の補足欄に記述したようなDO~LOOPを使わなければならないという発想は私の勘違いでしょうか、といったようなことになるでしょう。

関連するQ&A

  • ExcelにおけるVBAで、データの振り分けをしたい

    Sub a() Dim i As Long Dim s As Long Dim b As Worksheet Dim c As Worksheet Dim maxi As Long Dim maxs As Long Application.ScreenUpdating = False With ThisWorkbook Set b = .Worksheets("bbb") Set c = .Worksheets("ccc") End With maxi = b.Range("A1").CurrentRegion.Rows.Count maxs = c.Range("A1").CurrentRegion.Rows.Count For i = maxi To 2 Step -1 For s = maxs To 2 Step -1 If c.Cells(s, 1) = b.Cells(i, 1) And c.Cells(s, 2) = b.Cells(i, 2) Then c.Cells(s, 14) = b.Cells(i, 3) End If Next s Next i Application.ScreenUpdating = True End Sub ワークシートcとワークシートbの1列目と2列目が一致したときにだけ、cの14列目にbの3列目のデータを代入したく思い、以上のようなコードを書きましたが、重くて終わる様子がありません。 ・そもそもあっているのか、あっていないならどこを修正すればよいか ・早く終わるようにするにはどうしたらいいか アドバイスをよろしくお願いします。

  • エクセルの行の削除を配列で高速化したい

    A列にID番号(012345等の文字列化した数字) B列に属性(A、B、C等の文字列) C列に数値  のようなデータがあります。 1行目はタイトル行です。 最優先されるキーをA列、2番目に優先されるキーをB列にして並べ替えてあります。 A列、B列のデータは重複するものがあります。 このデータを、 A列のID番号が同じだった場合、上の属性がA、次の行の属性がBの組み合わせだった場合のみ、下の行のC列の数値データを上の行のC列の数値に加算して、下の行を削除します。 以下のマクロを書き、うまくいきました。 Sub 集計() Dim i As Long, r As Long r = Cells(65536, 1).End(xlUp).Row Application.ScreenUpdating = False For i = r To 2 Step (-1) If Cells(i, 1) = Cells(i - 1, 1) Then If Cells(i, 2) = "B" And Cells(i - 1, 2) = "A" Then Cells(i - 1, 3) = Cells(i - 1, 3) + Cells(i, 3) Rows(i).Delete End If End If Next Application.ScreenUpdating = False End Sub しかし、データ数が多いので1分以上かかってしまいます。 多分、配列に取り込んで処理できれば飛躍的に高速化できるとは思うのですが、 V = Range(Cells(2, 1), Cells(r, 3)).Value と取り込んだあと、どう処理したらいいのかわかりません。 教えてください。

  • エクセルのマクロについて

    下記は、A列3行の7文字目~10文字と B列5行~文字のある最後の行までの範囲の左から1文字目~4文字 に相違がある場合 MsgBox i & “行目” を出す。 というマクロなのですが、『B列5行~文字のある最後の行までの範囲』の中でも『空白のセルに関してはMsgBox不要』というふうに付加えたいのですがどのようにすればよいでしょうか。 Sub Macro1() Dim i As Long Dim sOrgText As String Dim ltotal As Long With ActiveSheet sOrgText = Mid(.Cells(3, 1), 7, 4) ltotal = .Cells(65536, 2).End(xlUp).Row For i = 5 To ltotal If Not Mid(.Cells(i, 2), 1, 4) = sOrgText Then MsgBox i & "行目" End If Next i End With End Sub

  • エクセルVBA  どうしても動きません。

    お世話になります。 なかなか上達しない超初心者です。 ↓↓ですが、Activesheetにすると動くのに、シート名を元々存在するシート”実験"に指定すると動きません(データ内容はまったく同じで、A列に色んな名前が入っていて、重複しているとC列に重複と入力します)。 2日間試行錯誤したのですが、やっぱり動かず・・・ ちなみに、Activateにするとアクティブになるし、CurrentRegionも選択できるのに なんでうごかないんでしょうか・・・ 何卒ご指導くださいませ。よろしくお願いいたします!!!!!! Sub Test2() With Sheets("実験").Range("A1").CurrentRegion Dim i As Long Dim LastRow As Long LastRow = Range("A" & Rows.Count).End(xlUp).Row For i = 1 To LastRow If WorksheetFunction.CountIf(Range("A:A"), Cells(i, 1)) > 1 Then Cells(i, 3) = "重複" End If Next i End With End Sub Sheets("実験")をActivesheetに変えると別のシートがしっかり動いてくれます・・・が、なんとしてでも”実験”シートに動いていただきたいです・・・。

  • 配列に格納したデータを指定行以下に転記する方法

    excel2000を使っています。 以下のコードだと最終行にデータが転記されます。これを4行目に確定して、転記したいのです。常に4行目つまりA列4行目以下に上書きしたいのです。 その場合コードをどのように変更すべきでしょうか? Sub 配列() With ActiveSheet ' 配列に格納 --------------------------- Dim i As Integer Dim LastRow As Long Dim SaleAry As Variant ' 配列に格納 --------------------------- SaleAry = Array(.Range("t4"), .Range("e5"), .Range("g5"), .Range("o5")) End With ' 転記 --------------------------- With Worksheets("daityou") LastRow = .Range("A65536").End(xlUp).Row For i = 0 To UBound(SaleAry) .Cells(LastRow + 1, i + 1).Value = SaleAry(i) ' Next i End With Set SaleAry = Nothing End Sub

  • Excelで複数セルからの文字の結合

    B列からF列までのセルの内容を結合してH列に表示させるため、 以下のVBAを使用したのですが、結果が上手くいきません 原因など分かりましたら、指摘をお願いします マクロの内容 Sub test01() Dim c As Range Dim i As Long With ActiveSheet i = 1 Do While .Cells(i, "A") <> "" If .Cells(i, "A") <> "" Then For Each c In .Range(.Cells(i, "B"), .Cells(i, "B").Cells(i, "F")) .Cells(i, "H") = IIf(.Cells(i, "H") = "", c, .Cells(i, "H") & "/" & c) Next c Else .Cells(i, "H") = .Cells(i, "B") End If i = i + 1 Loop End With End Sub シートの内容  ABCDEFGH 1 1あいうえお 2 2か くけこ 3 3さし せそ 実行の結果 あ/い/う/え/お/ か/き/く/け/こ//さ/し//せ/そ/ さ/し//せ/そ///////////// 上記のようになってしまいます 2行目の「か/き/く/け/こ」の後に1行下の「さ/し//せ/そ」 が入っている状態です よろしくお願いします

  • エクセルのVBAの記述について

    VBAの記述についてなのですが、 Sub filter() Dim gyo As Long Dim ws1 As Worksheet Dim ws2 As Worksheet Dim ws3 As Worksheet Set ws1 = Worksheets("データ") Set ws2 = Worksheets("チーム") Application.ScreenUpdating = False ws2.Range("A4:BH30").Clear gyo = ws1.Range("A65536").End(xlUp).Row ws1.Activate With ws1.Range(Cells(4, 1), Cells(gyo, 6)) .AutoFilter Field:=1, Criteria1:="A" .SpecialCells(xlCellTypeVisible).Copy ws2.Range("A4") Selection.AutoFilter End With Application.ScreenUpdating = True End Sub ならプログラムははしるのですが、 14行目を .SpecialCells(xlCellTypeVisible).Copy ws2.Range(Cells(4, 1)) だと 「実行時エラー 1004 Rangeメソッドは失敗しました Worksheet オブジェクト」 とでるのですが、出来ないのでしょうか? Cells(4, 1)の1のところを変数にして変えていきたいのですが、よい方法はありますか。 よろしくお願いいたします。

  • グラフの「項目軸ラベルに使用」をVBAで

    VBAで項目軸ラベルの範囲を設定したいのですが分からないので教えてください。データ系列は以下で入れられるのですが・・・ Dim R1 as Range Dim R2 as Range Dim n as Integer Range("a1").Select n=range("h1").value Set R1 =Range(Cells(1,1),Cells(n,1)) Set R1 =Range(Cells(1,2),Cells(n,2)) Sheets("グラフ").Select With ActiveChart .SetSourceData R1 たぶんここに入れるのでは・・・ End With Set R1 = Nothing Set R2 = Nothing

  • ExcelのVBAで質問です。

    以下のようなシートがあります。 A列  B列  C列  D列  E列  F列  G列  H列 NO  名前  確認 日付1 日付2  確認 日付1 日付2 6行目からデータを入れる予定です。 C列には○印を入力します。 C列~E列までデータが入った行は、 F列~H列まで同じ処理をします。 (セルの背景色を変えます。) 以後同じことを列方向で繰り返します。 以下のようなVBAを組みましたが、 ○の個数を数える部分でエラーがでます。 Private Sub Worksheet_Change(ByVal Target As Range) Dim staff As String Dim kakunin As String Dim date1 As Date Dim date2 As Date Dim i As Long Dim j As Long Dim cnt As Long '100件分ループ For i = 6 To 105 '○の数をカウント cnt = WorksheetFunction.CountIf(ActiveSheet.Range(Cells(i, 2), Cells(i, 256)), "○") 'jとは確認の列番号のこと j = 3 * cnt staff = Cells(i, 2) kakunin = Cells(i, j) date1 = Cells(i, j + 1) date2 = Cells(i, j + 2) 'スタッフ名が入力されたら If staff = "" Then Range(Cells(i, j), Cells(i, j + 50)).Interior.ColorIndex = 15 Else Cells(i, j).Interior.ColorIndex = xlNone '○が入力されたら If kakunin = "○" Then Range(Cells(i, j + 1), Cells(i, j + 2)).Interior.ColorIndex = xlNone Else Range(Cells(i, j + 1), Cells(i, j + 2)).Interior.ColorIndex = 15 End If If Cells(i, j + 1) <> "" And Cells(i, j + 2) <> "" Then Cells(i, j + 3).Interior.ColorIndex = xlNone End If End If Next i End Sub ご教授いただけたら、幸いです。 よろしくお願いいたします。

  • 条件に合った行を削除するマクロについて

    こんにちは 今、現在、とある条件にあった行を削除するマクロ作っているのですが、 インターネットを調べてみると後ろから探索して、1行ずつ消していくのがいいと書いてありました。 まぁ、その理屈はわかるんですが、それなら 「Unionでセルの範囲を結合してから、最後に一度に消してしまった方が速いのでは」 (消す作業が1度だけで済むから) と思い試してみたんですが、実際試したところ・・・ ものすごく遅かったです。 (ちなみに、1万件のデータで削除した行数は6000ほどでした) 何故Union結合だと遅いのでしょうか? 速いマクロを作成するには、やはり後ろから探索して、1行ずつ消していくしかないのでしょうか? 以下は試したマクロです。 (test が unionで試したマクロ、test2が後ろから1行ずつ削除したマクロ) Option Explicit Public Sub test() Dim r As Range Dim r1 As Range 'Cells.Replace "-", " " For Each r In Range("A2", Range("A65536").End(xlUp)) If r = r.Offset(1, 0) And r.Offset(0, 1) < r.Offset(1, 1) Then If r1 Is Nothing Then Set r1 = r Else Set r1 = Union(r1, r) End If End If Next r1.EntireRow.Delete ' r1.Select End Sub Public Sub test2() Dim r As Range Dim r1 As Range Dim i As Integer 'Cells.Replace "-", " " Application.ScreenUpdating = False For i = Range("A65536").End(xlUp).Row To 1 Step -1 If Cells(i, 1) = Cells(i + 1, 1) And Cells(i, 2) < Cells(i + 1, 2) Then Cells(i, 1).EntireRow.Delete End If Next Application.ScreenUpdating = True End Sub

専門家に質問してみよう