質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

Q&A

解決済

3回答

576閲覧

【VBA】優先度を判定し重複行の削除をしたい

yosy

総合スコア4

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

1グッド

0クリップ

投稿2024/08/29 04:14

実現したいこと

CA列に重複がある場合、優先度判定を行い、優先度の低い重複行をすべて削除したい。
データは6千行ほどあり、VBAで処理したいです。
CB列は文字列(1.***** 2.*****)となっており、左から先頭一文字目が1~7の数字となるのでまずこれを抽出する。

優先度の判定
・CB列の数字が小さい行を優先する
・CB列の数字が同じ場合、A列の数字が大きい行を優先する

行番号 CA列 CB列
1   x   1
2   y   4
3   x   3
4   y   4
5   z   6
6   x   2

例えば上記の例だと、
行番号1・3・6がCA列重複→CB列の優先度1が最も高いので3・6行目は削除
行番号2・4がCA列重複→CB列の優先度は同じ→A列の優先度4が高いので2行目は削除
行番号5は重複なしなので残す

発生している問題・分からないこと

辞書機能を使って既存の行と現在の行での比較(2行分の比較)しかできず、どうやっても
3行以上の比較が分からなかったので質問しました。

該当のソースコード

特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

Googleでは優先度を判定する重複行削除の例が見つかりませんでした。

補足

特になし

tatsu99👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2024/08/29 04:38

> 辞書機能を使って既存の行と現在の行での比較(2行分の比較)しかできず、どうやっても3行以上の比較が分からなかったので質問しました。 どういうコードを書いたのでしょうか?
hatena19

2024/08/29 04:43

エクセルのバージョンは何でしょうか。 それによって使える関数や機能が異なりますので。
tatsu99

2024/08/29 05:23

>行番号2・4がCA列重複→CB列の優先度は同じ→A列の優先度4が高いので2行目は削除 提示された例では、A列の情報はありませんが、「A列の優先度4」は、どのようにしてわかるのでしょうか。
yosy

2024/08/29 05:28

hatena19様 こちらになります。 Microsoft® Excel® for Microsoft 365 MSO (バージョン 2408 ビルド 16.0.17928.20114) 64 ビット VBAでの処理をしたいと思っています。
yosy

2024/08/29 05:29

tatsu99様 A列はシンプルに数字ですので、1~6000の番号が入っております。 提示漏れ申し訳ありません。
yosy

2024/08/29 05:31

meg_様 当初はBX列に契約番号が入っているかいないかで優先度を決めていたので 現在の要望とは少し違いますが、下記のように記述しておりました。 全くの初心者で、契約番号がどちらも入っている場合などの考慮ができておらずお恥ずかしいです。。 ' 重複チェックと優先順位による行の削除 Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") ' CA列の重複をチェックし、行番号を保存 For i = lastRow2 To 2 Step -1 cellValue = ws2.Cells(i, "CA").Value If cellValue <> "" Then If Not dict.exists(cellValue) Then dict.Add cellValue, i Else ' 優先順位の決定 Dim existingRow As Long existingRow = dict(cellValue) If ws2.Cells(i, "BX").Value <> "" And ws2.Cells(existingRow, "BX").Value = "" Then ' 既存の行に契約番号がない場合、既存の行を削除 ws2.Rows(existingRow).Delete dict(cellValue) = i ' 現在の行を辞書に保存 ElseIf ws2.Cells(i, "BX").Value = "" And ws2.Cells(existingRow, "BX").Value <> "" Then ' 現在の行に契約番号がない場合、現在の行を削除 ws2.Rows(i).Delete Else ' 他の場合は比較し、A列の数字が大きい方を残す If ws2.Cells(i, "A").Value > ws2.Cells(existingRow, "A").Value Then ws2.Rows(existingRow).Delete dict(cellValue) = i ' 新しい行を辞書に保存 Else ws2.Rows(i).Delete End If End If End If End If Next i
guest

回答3

0

これだめだな多分。3 で破綻だな。ソート列の値がソートで入れ替える都度変わってしまいそう。
もう一つの列に 0,1を入れる というのが式でできれば良いけど。。。
あ!
もう一つの列にその列の値をpastで良いか
以下駄目な案晒しておきます
ーーーーーーーーーーーーーーーーーーーー
一回ポッキリなら全部手作業でできるんじゃないかな。

1 CA, CB, A(逆順) でソートする
2 空いている列に式 上の行のCAとこの行のCAが等しかったら1違ってたら0
3 その列でソート
4 その列が1である先頭行を見つけ、そこから下を削除
5 その列を削除
6 Aでソート
7 Aをリナンバー

これが 一番早く答えが得られるような気がする

投稿2024/08/29 23:19

編集2024/08/29 23:27
winterboum

総合スコア23549

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yosy

2024/08/30 04:56

色々と考えていただきありがとうございます! 1回ぽっきりなら手作業でもちろん済ませるのですが、週に3回作業がありまして、 膨大な量なので今回VBAにチャレンジしてみた次第です。。。 情報記載出来ておらず申し訳ございません。
winterboum

2024/08/30 07:18 編集

週3回! でしたら 私の最初の回答で、sortもVBAでやるのが簡明かと。
guest

0

ベストアンサー

優先度の判定
・CB列の数字が小さい行を優先する
・CB列の数字が同じ場合、A列の数字が大きい行を優先する

CB列の先頭一文字×10000-A列の値 を比較するようにすればいいでしょう(A列の値が4桁以内の場合、桁数が多い場合はそれに合わせて×数値を増やします)。

辞書機能を使って既存の行と現在の行での比較(2行分の比較)しかできず、どうやっても
3行以上の比較が分からなかったので質問しました。

3行以上の比較をする必要はないのでは。
最終行から上に移動しながら、
辞書のキーにCA列の値、アイテムに行番号を登録していく、
CA列の値がキーにすでに存在する場合は、アイテムの行と現行の上記の比較値を比べて、比較値が大きいほうの行を削除して、小さいほうの行番号をアイテムに格納する。
これを先頭行まで繰り返せば、比較値の最小の行のみ残ります。

これで希望の結果に得られます。

訂正

上記のロジックですが、行番号を格納してそれを元に削除すると、削除することによってそれ以降の行が上に移動するので、格納した行番号とずれてしまいます。
実際にコード化して気が付きました。
ということで、下記のロジックに訂正します。

最終行から上に移動しながら、
辞書のキーにCA列の値、アイテムに比較値を登録していく、
CA列の値がキーにすでに存在する場合は、小さいほうの比較値をアイテムに格納する。
これを先頭行まで繰り返すとキーに対応する優先度のもっとも高い比較値が格納されます。

再度、最終行から上に移動しながら、
現在行の比較値と辞書の比較値(もっとも優先度の高い値)が一致しない行を削除する。
これを先頭行まで繰り返すと優先度の高い行のみ残る。

上記をコード化したコードが下記になります。

vba

1Public Sub Sample() 2 Dim dic As Object 3 Set dic = CreateObject("Scripting.Dictionary") 4 Dim tbl As Range 5 Set tbl = Worksheets(1).Cells(1, 1).CurrentRegion 6 7 Dim i As Long 8 For i = tbl.Rows.Count To 2 Step -1 9 Dim ky As String, pv As Long 10 ky = tbl.Cells(i, "C").Text 11 pv = Left(tbl.Cells(i, "D"), 1) * 10000 - tbl.Cells(i, "A") 12 If dic.Exists(ky) Then 13 If dic(ky) > pv Then 14 dic(ky) = pv 15 End If 16 Else 17 dic(ky) = pv 18 End If 19 Next 20 21 For i = tbl.Rows.Count To 2 Step -1 22 ky = tbl.Cells(i, "C").Text 23 pv = Left(tbl.Cells(i, "D"), 1) * 10000 - tbl.Cells(i, "A") 24 If dic(ky) <> pv Then 25 tbl.Rows(i).Delete 26 End If 27 Next 28End Sub

別案 式とフィルターを利用して手作業で

表範囲の右隣の空列の1行目に「比較値」と入力。
2行目に下記の式を設定する。
=LEFT(CB2,1)*10000-A2
フィルハンドルをダブルクリックすると最終行まで比較値が表示される

さらに右隣の列の1行目に「優先行」と入力。
2行目に下記の式を設定
`=MINIFS(CC$2:CC$6000,CA$2:CA$6000,CA2)=CC2
※CC は比較値の式を設定した列アドレス
フィルハンドルをダブルクリックすると最小比較値と一致する行はTRUE、不一致の行はFALSEとなる。

「優先行」列でフィルターをかけてFALSEの行を抽出する。
表示されている行を行削除する。
フィルターを解除する。
作業列2列を削除する。

以上。

投稿2024/08/29 07:03

編集2024/08/30 00:34
hatena19

総合スコア34064

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatsu99

2024/08/29 07:34

>CB列の数字が同じ場合、A列の数字が大きい行を優先する ということなので、 CB列の先頭一文字×10000+A列の値 を比較する のではなく CB列の先頭一文字×10000-A列の値 を比較する のが正しいのではないでしょうか。
hatena19

2024/08/29 08:59

> CB列の先頭一文字×10000-A列の値 を比較する > のが正しいのではないでしょうか。 どちらも小さいときと誤読してました。 ご指摘ありがとうございます。 回答の方は修正しておきます。
yosy

2024/08/30 08:37

hatena19様 提示していただいたコードの、下記部分だけ修正したら思い通りの結果になりました…!!! pv = Val(Left(tbl.Cells(i, "C"), 1)) * 10000 - tbl.Cells(i, "A") 比較値の考え方などとても参考になりました。 本当にありがとうございました!
guest

0

目的から見て一回しか通さないプログラムだと思われます。でしたらすべてをVBAにやらせるのではなく、前処理を手で行い、後処理も手で行えばスッキリしたcodeになると思います。「CBの先頭文字を抜き出す」処理も要らないし、 辞書などと大物を持ち出さなくても済みます。辞書検索もなくなるから処理も早くなるかなぁ。。
前処理も後処理もソートですのでそれもVBAで行っても良いですが。

前処理
CA, CB, A(逆順) でソートする

処理
下から2行づつ CA を比較し
・同じだったら下の行を削除。
・違ったら下の行を残し、新しい CA に移る

後処理
A でソート(必要なら)
Aの番号の付け直し(必要なら)

投稿2024/08/29 23:10

編集2024/08/29 23:12
winterboum

総合スコア23549

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問