[[20230801185706]] 『キーを検索し上にあるセルをキーの下と入れ替えた』(麦茶) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『キーを検索し上にあるセルをキーの下と入れ替えたい』(麦茶)

シフト作成で9:00〜15:00までA列にセルが並んでいます。
値がブロックのセルの上の「出」をブロックの下へ移動したいのですができません。下記では「出」がコピーされるだけなのですがどこを変更したら良いかおしえてください。
Sub Sample()
Dim fnd As Range, key
key = "ブロック"
Set fnd = Range("A:A").Find(key, LookAt:=xlWhole)
If fnd Is Nothing Then Exit Sub
fnd.Offset(-1).Copy
fnd.Offset(-1).Insert Shift:=xlDown
End Sub

  A
9_出
10_出
11_出
12_ブロック
13_昼
14_出
15_出
16_出
17_出

< 使用 Excel:unknown、使用 OS:unknown >


 Sub test()
     Dim r As Long
     r = WorksheetFunction.Match("ブロック", Range("B1").Resize(Cells(Rows.Count, "A").End(xlUp).Row), 0)
     Cells(r - 1, 1).Resize(, 2).Cut
     Cells(r + 1, 1).Resize(, 2).Insert Shift:=xlDown
 End Sub
(フォーキー) 2023/08/01(火) 19:42:19

 すみません、麦茶さんのコード見てませんでした。
 途中まで完成してましたね。
 マクロの記録をすれば分かると思いますが、行列の入れ替えはコピーではなくカットです。
 あとオフセットの引数は省略しないほうがいいらしいです。(office田中さんが言ってた気がします)

 Sub Sample2()
     Dim fnd As Range, key
     key = "ブロック"
     Set fnd = Range("A:A").Find(key, LookAt:=xlWhole)
     If fnd Is Nothing Then Exit Sub
     fnd.Offset(-1, 0).Cut
     fnd.Offset(1, 0).Insert Shift:=xlDown
 End Sub
(フォーキー) 2023/08/01(火) 19:47:18

 セルの値だけ入れ替えれば良いのなら、こんなことで済むのでは?

 Sub Sample()
     Dim fnd As Range
     Dim key As String
     Dim v As Variant

     key = "ブロック"
     Set fnd = Range("A:A").Find(key, LookAt:=xlWhole)
     If fnd Is Nothing Then Exit Sub

     v = fnd.Offset(-1).Value
     fnd.Offset(-1).Value = fnd.Value
     fnd.Value = v
 End Sub
(xyz) 2023/08/01(火) 20:17:52

フォーキーさん xyzさん ありがとうございます。
説明不足ですいません。
図にあります。12時の「ブロック」の位置はそのままで、11時の「出」と13時の昼を入れ替えることは可能でしょうか。複雑なコードで理解できないようでしたら御指南いただいたコードで行こうと思ってます。

(麦茶) 2023/08/01(火) 22:54:56


 おわりの3行を
    v = fnd.Offset(-1).Value
    fnd.Offset(-1).Value = fnd.Offset(1).Value
    fnd.Offset(1).Value = v
 とすればよいのでは?

 というよりも私の最初の回答が間違っていたのかな。
 他人に回答に先に目が行き、質問をよく読んでいなかったです。
 失礼しました。
 # 回答修正。

(xyz) 2023/08/01(火) 23:08:57


xyzさん ありがとうございます。
変数vを増やすところは何となくイメージできましたが、
    v = fnd.Offset(-1).Value
    fnd.Offset(-1).Value = fnd.Offset(1).Value
    fnd.Offset(1).Value = v
この3行を順番に動かすなんてイメージできませんでした。
ありがとうございます。助かりました!
(麦茶) 2023/08/02(水) 00:16:57

>値がブロックのセルの上の「出」をブロックの下へ移動したい
私が分かってないだけかもですが、単純に見つけたセルを1つ上のセルにカット&インサートするだけじゃダメなんですか?

    Sub さんぷる()
        Dim fnd As Range

        Set fnd = Range("A:A").Find("ブロック", LookAt:=xlWhole)
        If Not fnd Is Nothing Then
            fnd.Cut
            fnd.Offset(-1).Insert Shift:=xlDown
        End If
    End Sub

(もこな2) 2023/08/02(水) 07:55:10


もこな2さん
ブロックは元の時間から動かさず取っておきたいので少し違います。

(麦茶) 2023/08/02(水) 16:12:18


先日教えていただいたコードを少し変えてみましたがエラーになります。
条件が変わってシフト作成で縦に9:00〜17:00まで横にA〜I列までセルが並んでいます。
値がブロックのセルの上の「出」をブロックの下の「休」と入れ替えたいのですができません。

  C____D___E・・・・
9_     出
10_     出
11_出    出  出
12_ブロック 出  ブロック
13_昼       休
14_出
15_休
16_出
17_出

Sub sumple3で検索範囲をRange("C4:C14")だけだと入れ替えができるのですが
Sub sumple3()

    Dim fnd1 As Range, fnd2 As Range
    Dim key1 As String, key2 As String
    Dim v As Variant, i As Variant
    key1 = "ブロック"
    key2 = "休"
        Set fnd1 = Range("C4:C14").Find(key1, LookAt:=xlWhole)
        Set fnd2 = Range("C4:C14").Find(key2, LookAt:=xlWhole)
        If fnd1.Offset(-1) = "出" Then
        If fnd1 Is Nothing Then Exit Sub
            v = fnd1.Offset(-1).Value
            fnd1.Offset(-1).Value = fnd2
            fnd2.Value = v
        End If
End Sub

sumple4で検索範囲を横に広げたつもりの下記だと実行時エラー91 オブジェクト変数または With ブロック変数が設定されていません。とエラーになります。解決策を教えてください。

Sub sumple4()

    Dim fnd1 As Range, fnd2 As Range
    Dim key1 As String, key2 As String
    Dim v As Variant, i As Variant
    key1 = "ブロック"
    key2 = "休"
    For i = 3 To 9
        Set fnd1 = Range(Cells(4, i), Cells(14, i)).Find(key1, LookAt:=xlWhole)
        Set fnd2 = Range(Cells(4, i), Cells(14, i)).Find(key2, LookAt:=xlWhole)
        If fnd1.Offset(-1) = "出" Then
        If fnd1 Is Nothing Then Exit Sub
            v = fnd1.Offset(-1).Value
            fnd1.Offset(-1).Value = fnd2
            fnd2.Value = v
        End If
    Next
End Sub

(麦茶) 2023/08/03(木) 23:53:52


fnd1またはfnd2がNothingでも
If fnd1.Offset(-1) = "出" Thenや fnd2.Value = vみたいな処理をしようとして
エラーが出ているのかも?

サンプルデータにもD列には「ブロック」や「休」がありませんから
ここで検索をかけるとfnd1,fnd2は空のまま。
それに対してoffsetやValueをつけるとエラーになります。
(火災報知器) 2023/08/04(金) 01:50:53


 エラーの原因は火災報知器さんの指摘通りだと。

 Findしたあと、結果が Nothing でないか確認してから次の処理に進むようにしましょう。

 あと、Forループ内で Exit Sub しちゃうと「ブロック」が見つからないとき、
 それ以降の列の処理が実行されません。

    For i = 3 To 9
        Set fnd1 = Range(Cells(4, i), Cells(14, i)).Find(key1, LookAt:=xlWhole)
        If Not fnd1 Is Nothing Then 
            If fnd1.Offset(-1) = "出" Then
                Set fnd2 = Range(Cells(4, i), Cells(14, i)).Find(key2, LookAt:=xlWhole)
                If Not fnd2 Is Nothing Then
                    v = fnd1.Offset(-1).Value
                    fnd1.Offset(-1).Value = fnd2
                    fnd2.Value = v
                End If
            End If
        End If
    Next

(hatena) 2023/08/04(金) 02:57:08


  お二方から回答いただいたとおりかと思います。

  いくつか蛇足を。
 (1)変数の型  
    当初、セルの内容が色々なものがあるかと想像し、dim v As Variantとしましたが、
    このケースでは As Stringが適切でした。
    なお、Dim i As Variantは意味不明。Dim i As Longがよいでしょう。列番号という数値なので。

 (2)"休"は"ブロック"のあとにある"休"という意図でしょうから、
     Set fnd2 = Range(Cells(4, i), Cells(14, i)).Find(key2, After:=fnd1, LookAt:=xlWhole)
     として、"fnd1の次から検索する"のだ、という指示を出しておいたほうが安全です。

 (3)
      v = fnd1.Offset(-1).Value
      fnd1.Offset(-1).Value = fnd2.Value
      fnd2.Value = v
   の3行は、この種の話で出てくるお決まりのコードです。
   その都度書くのは面倒なので、
   「二つのセルの内容を入れ替える」というサブプロシージャにするとよいかもしれません。
   Sub myExchange(r1 As Range, r2 As Range)
       Dim v As Variant '数値文字列混在も考慮してあえてVariant
       v = r1.Value
       r1.Value = r2.Value
       r2.Value = v
   End Sub
   を追加作成します。
   こうしておけば、

   Call myExchange(fnd1.Offset(-1), fnd2)

   の一行で交換が完了します。
   また、コードを見ただけで意味(意図かな)が明確に読み取れます。一考してみては?

 (4)【まったく勝手な感想です。スキップいただいて結構です】
 全般に、色々なパターンがあるでしょうから、それらを逐一コードにしていると、
 どれを使うか迷いませんか?
 すべてをロジックに落とし込むことができれば、効率的ですが、
 所詮そういうものは、アドホックな処理になるので、
 フリーハンドの領域と割り切ることも有効かもしれません。

 例えば、
 ・Ctrlキーを押しながら二つのセルを選択して、
 ・その二つ値を交換するマクロを書き、
 それをなんらかのショートカットキーに登録しておいて
 それを使いまわすといった、原始的な方法のほうが、
 却って人間には使い勝手がいいかもしれません。

(xyz) 2023/08/04(金) 09:04:40


火災報知器さん >エラー原因の特定ありがとうございます。
hatenaさん >コードの提供ありがとうございます。
 Set 変数名 = セットするオブジェクト
 If Not 変数名 Is Nothing Then
 これでオブジェクトの状態を空にすることを理解しました。
xyzさん>丁寧なご教授ありがとうございます。
(4)については交換対象の2つのセルをダブルクリックすると入れ替わるマクロをシートに書いています。
実際は30名分のシフトを作っているのですが、変更が頻繁に発生し、ある程度まで条件設定し自動化できないかチャレンジしている次第です。(沼にはまった感がありますが。。。)
(3)サブルーチン化是非チャレンジしたいです。
直ぐに壁に突き当たりそうですがその際はよろしくお願いいたします。

(麦茶) 2023/08/04(金) 10:39:31


 > Set 変数名 = セットするオブジェクト
 > If Not 変数名 Is Nothing Then
 > これでオブジェクトの状態を空にすることを理解しました。

 「オブジェクトの状態を空にする」のではなく、
 「変数にオブジェクトが入っているかどうか」を判定してます。
 入っていないとエラーになるので、入っている場合のみ次の処理に進むようにしてます。

(hatena) 2023/08/04(金) 11:02:47


 After:=fnd1 の追加は、休がふたつあったら有効ですが、
 一巡りすれば、上にある"休"も検索してしまうので、
 検索範囲を限定して、fnd1.Rowから14行目までを検索するようにしないとダメですね。
 余り伝わっていないようですけど。

 >サブルーチン化是非チャレンジ
 というか、もう示したんですけどねえ。
 まあ、頑張ってください。
(xyz) 2023/08/04(金) 14:11:30

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.