ここから本文です

エクセルVBA、データ並べ替えの質問です。 2次元配列に並ぶデータがあります。 1...

アバター

ID非公開さん

2019/12/618:29:38

エクセルVBA、データ並べ替えの質問です。
2次元配列に並ぶデータがあります。
1 1 1 1 1 1
1 1 1 1 1 1
1 1
2 2 2 2 2 2
2 2 2 2 2 2
2 2
1セットのデータが14個、6個で改行、100セッ

ト並んでます。1 1 .と書いてますが、値はバラバラです。これを下記のように書き換えたいのです。
1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2

どうすればいいですか?マクロはよく組みますが、なかなか思い浮かびません。宣言等は分かります。核心部分を教えて欲しいのです。

補足14個、6個、100セットの数字は事前に分かってますが、配列により変わります。1つの配列内では一定です。

閲覧数:
185
回答数:
5
お礼:
50枚

違反報告

ベストアンサーに選ばれた回答

2019/12/810:17:08

せっかくの回答リクエストで恐縮ですが、返信に回答を書いてたため大元の回答から削除したので返信についてはこちらにも記録がありません。
また作成した際のブックも保存しておりませんので、その時のコードの提示は不可能となっております。
ので私の考えた内容について。

まずセルに書き込む値を『1,1,1,1,1・・・』ではなく『1~14』の値にしてみると思い浮かんできますよ。
最初は1グループだけでやってみると。
ちょっとした数学の応用みたいなものですから。

★代入式の左辺は多分おわかりになるのでしょう。
問題は右辺の方ですよね?
セルで言うなら、

・行については3行を全てインデックス:1にまとめたい。
別配列へは For n=1 To 14 としておけば左辺の2次側としてそのまま変数:nは使えます。(1次側は後程)

では右辺のセル行を3つから1つにするには?
6列毎に区切る点はお分かりかと思います。

n \ 6 だと商はnが1~5までは0に、6の時1になってしまうので都合が悪い。

なので、

(n - 1) \ 6 であればnが1~6の時、-1の効果で商は全て0となりますが、0行目と言うのはないですよね?

なので、

(n - 1) \ 6 + 1 としておけば後の+1により1次側は1行目を選択します。

2行目についてもn:7~12の商は全て1であり+1によって2行目を選択します。

3行目については値がある部分が中途半端である事を悩んでおられるようですが、n:13~14と2つしかループしませんので自動的に3行目の3列目以降は無視されます。

・列については行毎に1~6を繰り返したい。

n Mod 6 とすることで剰余は1,2,3,4,5,0となっていきますが、0列目はありません。

従ってIIf関数で、

IIf(n Mod 6 = 0, 6 ,n Mod 6)

としておき6列目【剰余が0】の時は『6列目を指定』させます。それ以外の時は通常の剰余を値とします。

これで1グループ分の『内側のループ』です。

★グループ数が確実に100など固定化されている【ありがちな最終行を求める必要がない】場合。

『外側のループ』として

For m = 1 To 2 '質問文の件とテストを兼ねて

としておきましょう。
ここは代入式の左辺の1次側に直結します。

列につきましては例えどのグループでも上記のままになります。(内側のループで決めてますので)
問題は行の方ですが、3行毎のループですので

(n - 1) \ 6 + 1

のままでは永遠にインデックス:1の所に上書きをしてしまいます。
なのでジャンプ【Offset みたいな感じ】させていきます。

(n - 1) \ 6 + 1 + (m - 1) * 3

とします。(m - 1) * 3 の意味合いは1グループ目は既に式が出来ているので 0 * 3 = 0 を加算させるためです。

---

ここまでが考え方として私が思いついた内容です。代入式の右辺がセルであっても2次元配列であっても、行列又はインデックスを与える方法としては同じかなと。

ただ100グループ自体が変動であった場合は、ReDim の性質上1次と2次を逆転させて別配列は受けなければならないと言うのがありますけど。

ところで書き直す配列については、インデックスの初期値は 1 で宜しいのですよね?
0 から始めたいってなると修正が入ると思いますけど。

  • アバター

    質問者

    ID非公開さん

    2019/12/813:45:54

    ありがとうございます。インデックス初期値は1です。
    下記でどうでしょう?
    for m=1to LastRow/3
    for n=1 to 1 to 14
    rw=(n-1)/6+(m-1)*3+1
    cl=(n-1)mod6 +1
    Arr2(m, n)=Arr1(rw, cl)
    next n
    next m

    「3 」の求め方
    dim k as long
    k=14/6
    if k*6<14 then k=k+1

  • その他の返信を表示

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

アバター

質問した人からのコメント

2019/12/10 21:41:09

多数の方に回答を頂き、無事に解決しました。ありがとうございます。ただの並べ替えでもひねりが入ると難しく、まだまだ修行が足りないと思いました。

ベストアンサー以外の回答

1〜4件/4件中

並び替え:回答日時の
新しい順
|古い順

30246kikuさん

2019/12/910:28:16

雰囲気、以下でどうなりますか

確認は

新規ブックを開き、標準モジュールに以下を記述します
testData を実行し確認用データを作成後、Samp1 を実行してみます

確認用の配列を簡単に用意するため、
★部分で入手 & 結果書出ししてますが・・・・

なお、▼ 部分の変更だけで、色々動くと思います
※ 計算で位置を求めたりすると、以降変更し難くなるのかも??

どうなりますか


Option Explicit

Public Sub Samp1()
   Dim vA As Variant, vC As Variant, vR As Variant, v As Variant
   Dim jR As Long, jC As Long
   Dim i As Long, j As Long, k As Long, n As Long, m As Long

   vC = Array(6, 6, 2) ' ▼ 抜き出しパターン
   m = UBound(vC) - LBound(vC) + 1
   n = 0
   For Each v In vC
      n = n + v
   Next

   vA = Range("A1").CurrentRegion ' ★ 元配列入手

   k = (UBound(vA) - LBound(vA) + 1) \ m

   If (k < 1) Then Exit Sub
   ReDim vR(1 To k, 1 To n)
   k = k * m + LBound(vA) - 1

   i = LBound(vA) - 1: jR = 0
   While (i < k)
      jR = jR + 1: jC = 0
      For Each v In vC
         i = i + 1
         For j = LBound(vA, 2) To LBound(vA, 2) + v - 1
            jC = jC + 1
            vR(jR, jC) = vA(i, j)
         Next
      Next
   Wend

   Range("I1").Resize(jR, n).Value = vR ' ★ 結果書出し
End Sub


' 確認用データ作成

Public Sub testData()
   Const CC As Long = 100 * 3
   Dim vA(1 To CC, 1 To 7) As Variant
   Dim i As Long, j As Long, k As Long

   k = 0
   For i = 1 To CC
      For j = 1 To UBound(vA, 2)
         k = k + 1
         vA(i, j) = k
      Next
   Next

   Cells.Delete
   Range("A1").Resize(CC, UBound(vA, 2)).Value = vA
   Columns.AutoFit
   Columns("I").Resize(, 14).ColumnWidth = _
      Columns("A").ColumnWidth
End Sub

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

プロフィール画像

カテゴリマスター

taihenda****さん

2019/12/813:19:06

配列だけを論議しているからわかりにくいです。

セルに書き出してしまえば目に見えるので意外と簡単、

A2:Fxの範囲をOrgという配列に入れます。
その配列を並び替えてDatという配列に入れます。
最後にDatをH2セルを先頭にしたセル範囲に書き出します。



Sub test()
Dim Org, Dat, i As Long, j As Long, k, l As Long, n As Long
n = Cells(Rows.Count, 1).End(xlUp).Row
Org = Range("A2:F" & n).Value
ReDim Dat(1 To Int((n - 1) / 3) + 1, 1 To 14)
For i = 1 To n - 1
If i Mod 3 = 1 Then
k = k + 1
l = 0
End If
For j = 1 To 6
If i Mod 3 = 0 And j > 2 Then
Exit For
Else
l = l + 1
Dat(k, l) = Org(i, j)
End If
Next
Next
Range("H2").Resize(UBound(Dat), 14) = Dat
End Sub

配列だけを論議しているからわかりにくいです。

セルに書き出してしまえば目に見えるので意外と簡単、...

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

kak********さん

2019/12/619:29:18

>1セットのデータが14個、6個で改行、
「14文字のデータが6文字ずつで改行されている」ということでしょうか?

単純に1,2、4、5番目の改行を削除すればよいのでは?
この並びが連続するのなら、3の倍数以外の改行を削除すればよいのでは。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

Ex3さん

2019/12/619:28:53

>核心部分

データが連続範囲にあるならば、Variant変数にCurrentRegionで2次元配列として読み込んでしまう。

もうひとつ、配列変数を用意して、For Nextループを多重にして先の2次元配列のデータを3行ごとにまとめて書き出していく。

終わったら、変換後の配列変数(Option Base 1 にしておく必要あり)をまとめてセルに書き出してしまう。

20行くらいのコードで十分です。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる