Chuyển từ mảng 2 chiều qua mảng 1 chiều (1 người xem)

  • Thread starter Thread starter thunoka
  • Ngày gửi Ngày gửi

Người dùng đang xem chủ đề này

T

thunoka

Guest
Chào các bạn,

Mình mới làm wen với VBA nên không biết làm sao để chuyển từ mảng 2 chiều sang mảng 1 chiều. Các bạn có thể coi hình này:

snaghtmlc6cfc0ec6.png


Cho mình hỏi là phải code như thế nào để có mảng như trên?

Mong các bạn giúp mình với! Cảm ơn các bạn nhiều lắm!
 
Chỉnh sửa lần cuối bởi điều hành viên:
Chào các bạn,

Mình mới làm wen với VBA nên không biết làm sao để chuyển từ mảng 2 chiều sang mảng 1 chiều. Các bạn có thể coi hình này:

snaghtmlc6cfc0ec6.png


Cho mình hỏi là phải code như thế nào để có mảng như trên?

Mong các bạn giúp mình với! Cảm ơn các bạn nhiều lắm!
Tạm làm như vầy đi cho dể hiểu nhé:
PHP:
Sub Test()
  Dim Rng As Range, Clls As Range
  Dim i As Long, j As Long, k As Long
  Set Rng = Range("B1:E3")
  For i = 1 To Rng.Columns.Count
    For j = 1 To Rng.Rows.Count
      Cells(6, k + 2) = Rng(j, i): k = k + 1
    Next
  Next
End Sub
 
Upvote 0
Chào các bạn,

Mình mới làm wen với VBA nên không biết làm sao để chuyển từ mảng 2 chiều sang mảng 1 chiều. Các bạn có thể coi hình này:

snaghtmlc6cfc0ec6.png


Cho mình hỏi là phải code như thế nào để có mảng như trên?

Mong các bạn giúp mình với! Cảm ơn các bạn nhiều lắm!

Chuyển thế này thì rất dễ, tuy nhiên không biết bài toán cụ thể của bạn là như thế nào vì có thể dùng Sub hoặc Function đều được hết.

Thân!
 
Upvote 0
Chào các bạn,

Mình mới làm wen với VBA nên không biết làm sao để chuyển từ mảng 2 chiều sang mảng 1 chiều. Các bạn có thể coi hình này:

snaghtmlc6cfc0ec6.png


Cho mình hỏi là phải code như thế nào để có mảng như trên?

Mong các bạn giúp mình với! Cảm ơn các bạn nhiều lắm!

Chào bạn,
Bạn xem đoạn code này:
PHP:
Sub HaiChieuToMotChieu()
RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
Zi = 0
For Each Cll In RngHaiChieu
Sheets("Sheet1").[B8].Offset(, Zi).Value = Cll
Zi = Zi + 1
Next Cll
End Sub
Và xem thêm file đính kèm nhé!
 

File đính kèm

Upvote 0
Chào bạn,
Bạn xem đoạn code này:
PHP:
Sub HaiChieuToMotChieu()
RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
Zi = 0
For Each Cll In RngHaiChieu
Sheets("Sheet1").[B8].Offset(, Zi).Value = Cll
Zi = Zi + 1
Next Cll
End Sub
Và xem thêm file đính kèm nhé!
Nhân có đoạn code của ca_dafi tôi phát hiện 1 chuyện hơi lạ:
Nếu:
RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao",Type:=8)
thì không có vấn đề gì
nhưng nếu:
Set RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao",Type:=8)
Thì kết quả trả về không đúng với yêu cầu.. Cụ thể trong trường hợp dưới nó duyệt range từ trái sang phải, xong mới từ trên xuống... Còn cách làm của ca_dafi thì nó duyệt từ trên xuống, xong mới từ trái sang phải
Sao thế nhỉ?
 
Upvote 0
Nhân có đoạn code của ca_dafi tôi phát hiện 1 chuyện hơi lạ:
Nếu:
thì không có vấn đề gì
nhưng nếu:
Thì kết quả trả về không đúng với yêu cầu.. Cụ thể trong trường hợp dưới nó duyệt range từ trái sang phải, xong mới từ trên xuống... Còn cách làm của ca_dafi thì nó duyệt từ trên xuống, xong mới từ trái sang phải
Sao thế nhỉ?

Ta có thể từ từ nghiệm ra vấn đề bằng cách thêm một Msgbox sau đây:
PHP:
Sub HaiChieuToMotChieu()
''Set RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)

RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
MsgBox RngHaiChieu.Address  ''<=== Thêm dòng này!
Zi = 0
For Each Cll In RngHaiChieu
Sheets("Sheet1").[B8].Offset(, Zi).Value = Cll
Zi = Zi + 1
Next Cll
End Sub
 
Upvote 0
Thêm 1 cách dùng công thức, nhưng hơi nhiêu khê:
- chuyển thành mảng dọc 1 chiều
- chuyển 1 lần nữa thành mảng ngang

Mới là ý tưởng, có thể bỏ bớt cột phụ, ô phụ
Cũng có thể sửa lại để chuyển trực tiếp thành mảng ngang theo ý tưởng đó.
Về lý thuyết có thể tăng kích thước mảng 2D tới giới hạn mà kết quả mảng ngang = 256 phần tử. (đã đặt name động cho mảng, nên tăng thử thoải mái)

TB: Thử xem khả năng tới đâu, chứ yêu cầu là VBA rõ rồi.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Hết nhiêu khê rồi, tất cả vào name.
Ghi chú cho file kèm theo: 3 dòng đầu chỉ để minh hoạ, có thể xoá.
 

File đính kèm

Upvote 0
Cảm ơn các bạn nhiều nha! Mình muốn hỏi thêm 1 cái nữa, đó là nếu có nhiều mảng 2 chiều, muốn chuyển thành nhiều mảng 1 chiều như hình dưới thì làm thế nào?

snaghtmlc6cfc0cb0.png


Mình muốn là kết quả sẽ hiển thị ở sheet khác. Cảm ơn các bạn nhiều nhiều! :)
 
Upvote 0
Mình muốn là kết quả sẽ hiển thị ở sheet khác. Cảm ơn các bạn nhiều nhiều! :)
Bạn có thể thêm một dòng để yêu cầu chọn vị trí cần xuất ra mảng một chiều là xong.
PHP:
Sub HaiChieuToMotChieu()
RngHaiChieu = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
Set RngMotChieu = Application.InputBox("Nhap O can xuat ra Mang Mot Chieu vao day", "Thong bao", Type:=8)
Zi = 0
For Each Cll In RngHaiChieu
RngMotChieu.Offset(, Zi).Value = Cll
Zi = Zi + 1
Next Cll
End Sub

Cảm ơn các bạn nhiều nha! Mình muốn hỏi thêm 1 cái nữa, đó là nếu có nhiều mảng 2 chiều, muốn chuyển thành nhiều mảng 1 chiều như hình dưới thì làm thế nào?
snaghtmlc6cfc0cb0.png
Bạn có thể chạy nhiều lần đoạn code này tương ứng với nhiều mảng hai chiều khác nhau!
 
Upvote 0
Xin góp 1 cách bằng công thức, càng kéo càng dài, kéo đê --=0
Đây là cách làm theo thuật toán chung của việc chuyển mảng từ 2D sang 1D. Dùng code VBA cũng có thể dùng theo công thức này cũng ra được.
 

File đính kèm

Upvote 0
Bài toán này có rất nhiều cách giãi: công thức và VBA
A> Bằng công thức:
Rất đơn giãn chỉ với 1 name duy nhất:
1> Đặt name cho vùng dử liệu:
2> Cuối cùng là công thức:
=INDEX(Rng,MOD((COLUMNS($A:A)-1),ROWS(Rng))+1,INT((COLUMNS($A:A)-1)/ROWS(Rng))+1)
Kéo fill công thức này sang phải, đến khi báo lổi thì dừng lại
Ghi chú: Công thức có thể đặt bất kỳ cell nào vẩn cho kết quả đúng
Công thức như của Rollover79 là chưa tổng quát đâu nhé (chú ý đến việc dùng ROWCOLUMN như có lần tôi đã nói... Lý ra phải là ROWSCOLUMNS )
B> Bằng VBA:
Nếu dùng vòng lập quét toàn bộ dử liệu thì dù 1 vòng lập hay 2 vòng lập, tốc độ vẩn như nhau (số lần quét đúng bằng tổng số cell hiện có của dử liệu)
Vậy để tăng tốc vòng lập ta dùng TRANSPOSE nhé
PHP:
Sub Test()
 Dim Rng As Range, TempRng As Range
 Set Rng = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
 For i = 1 To Rng.Columns.Count
   Set TempRng = Rng.Offset(, i - 1).Resize(, 1)
   Set Des = Range("B8").Offset(, (i - 1) * TempRng.Count).Resize(, TempRng.Count)
   Des.Value = WorksheetFunction.Transpose(TempRng)
 Next
End Sub
Với cách này, tốc độ tăng lên rất nhiều lần (dử liệu càng lớn sẽ càng thấy có sự phân biệt)
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Công thức như của Rollover79 là chưa tổng quát đâu nhé (chú ý đến việc dùng ROWCOLUMN như có lần tôi đã nói... Lý ra phải là ROWSCOLUMNS )
Tôi chưa hiểu chỗ này lắm, xin được chỉ giáo thêm, chưa tổng quát theo tôi hiểu là sẽ có trường hợp sai. Làm ơn chỉ dùm tôi là trường hợp nào sai được không?
(Tôi chưa đọc cái bài viết về việc dùng ROW COLUMN của bạn)
Cảm ơn!
 
Upvote 0
Tạo UDF :
PHP:
Function Mang1(ByVal Mang2 As Range) As Variant
Dim KQ(255)
h = Mang2.Rows.Count
C = Mang2.Columns.Count
For i = 0 To C * h - 1
    KQ(i) = Mang2((i Mod h) * C + Int(i / h) + 1)
Next i
Mang1 = KQ
End Function
Chọn vùng sẽ chứa mảng 1 chiều (một hàng nào đó bất kỳ, số lượng ô >= số lượng dữ liệu trong mảng 2 chiều), gõ công thức :
{=mang1(vùng dữ liệu mảng 2 chiều)} (dấu {} tương đương Ctrl-Shift-Enter)

Lấy ví dụ của thunoka :
Chọn vùng B9:M9, gõ {=mang1(B1:E3)}
Chọn vùng B10:M10, gõ {=mang1(B4:E6)}
 
Upvote 0
Mã:
Nguyên văn bởi [B]ndu96081631[/B]
Sub Test()
 Dim Rng As Range, TempRng As Range
 Set Rng = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
 For i = 1 To Rng.Columns.Count
   Set TempRng = Rng.Offset(, i - 1).Resize(, 1)
   Set Des = Range("B8").Offset(, (i - 1) * TempRng.Count).Resize(, TempRng.Count)
   Des.Value = WorksheetFunction.Transpose(TempRng)
 Next
End Sub
Nếu chạy với nhiều mãng, code bị báo lỗi.
 
Upvote 0
Tôi chưa hiểu chỗ này lắm, xin được chỉ giáo thêm, chưa tổng quát theo tôi hiểu là sẽ có trường hợp sai. Làm ơn chỉ dùm tôi là trường hợp nào sai được không?
Dể lắm... bạn cứ copy công thức của bạn rồi đặt nó vào 1 cell khác... Cũng làm thế với công thức của tôi ---> So sánh kết quả ---> Suy ra vấn đề
(Tôi chưa đọc cái bài viết về việc dùng ROW COLUMN của bạn)
Tôi không viết bài này nhưng đã có lần nhắc nhở (hình như là bạn hoangminhtien) về bài trích lọc danh sách duy nhất.. Trong file bạn ấy cũng đã từng dùng ROWCOLUMN (mà nếu tổng quát hơn thì phải là ROWS COLUMNS mới đúng)
Mục đich là làm cho công thức đúng ở mọi vị trí đặt, chỉ vậy thôi
Nói thêm: File chúng ta đưa lên chỉ là "giã lập" (file tác giã đưa lên cũng thế).. Nhưng dử liệu thật rất có thể nằm ở vị trí khác (khác dòng, cột)... Đến chừng đó họ áp dụng vào bị sai thế nào cũng la làng
Ẹc... Ẹc
 
Upvote 0
Mã:
Nguyên văn bởi [B]ndu96081631[/B]
Sub Test()
 Dim Rng As Range, TempRng As Range
 Set Rng = Application.InputBox("Nhap Mang hai chieu vao day", "Thong bao", Type:=8)
 For i = 1 To Rng.Columns.Count
   Set TempRng = Rng.Offset(, i - 1).Resize(, 1)
   Set Des = Range("B8").Offset(, (i - 1) * TempRng.Count).Resize(, TempRng.Count)
   Des.Value = WorksheetFunction.Transpose(TempRng)
 Next
End Sub
Nếu chạy với nhiều mãng, code bị báo lỗi.
Thầy ơi em chưa hiểu chổ này! Thầy giãi thích giúp em với
 
Upvote 0
Khi nhập vào Inputbox nhiều mãng 2 chiều (gọi theo chủ topic ) khác nhau, code trên bị báo lỗi. Để cho tổng quát hơn nữa, ndu xem lại chỗ này.
 
Upvote 0
Khi nhập vào Inputbox nhiều mãng 2 chiều (gọi theo chủ topic ) khác nhau, code trên bị báo lỗi. Để cho tổng quát hơn nữa, ndu xem lại chỗ này.
Có phải ý thầy muốn nói là chọn từ 2 vùng trở lên không liền nhau thì code sẽ báo lổi
Ví dụ: Vùng chọn là A1:B5,D5:F10,H9:K15
Nói chung thuật toán là dựa vào dử liệu thật mà hình thành... Nếu ý thầy đúng vậy thì em sẽ thêm 1 vòng lập nữa duyệt qua các Areas
(Em chưa rõ có hiểu đúng ý thầy không nên chưa đưa code lên)
 
Upvote 0
ndu đọc bài #9 sẽ thấy yêu cầu của bạn thunoka : muốn chuyển nhiều mãng 2 chiều thành nhiều mãng 1 chiều. Ý của mình đúng như bạn nói.
 
Lần chỉnh sửa cuối:
Upvote 0
ndu đọc bài #9 sẽ thấy yêu cầu của bạn thunoka : muốn chuyển nhiều mãng 2 chiều thành mãng 1 chiều. (Tuy nhiên hình mình họa chưa chuẩn lắm ). Ý của mình đúng như bạn nói.
Nếu vậy thì vẩn như em nói ở trên, em thêm vòng lập duyệt qua các Areas như sau:
PHP:
Option Explicit
Sub Test()
  Dim Rng As Range, TempRng As Range, Des As Range, StDes
  Dim i As Long, j As Long, k As Long
  On Error GoTo Thoat
  Set Rng = Application.InputBox("Chon vung du lieu nguon", Type:=8)
  Set StDes = Application.InputBox("Chon vung dat ket qua", Type:=8)
  For i = 1 To Rng.Areas.Count
    k = 0
    With Rng.Areas(i)
      For j = 1 To .Columns.Count
       Set TempRng = .Offset(, j - 1).Resize(, 1)
       Set Des = StDes.Offset((i - 1), k * TempRng.Count).Resize(, TempRng.Count)
       Des.Value = WorksheetFunction.Transpose(TempRng)
       k = k + 1
      Next j
    End With
  Next i
Thoat:   Exit Sub
End Sub
Có thể chuyển thoải mái nhiều mãng 2 chiều thành 1 chiều và đặt vùng kết quả sang bất cứ sheet nào
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Yêu cầu của tác giả là:
nếu có nhiều mảng 2 chiều, muốn chuyển thành nhiều mảng 1 chiều như hình dưới thì làm thế nào?
Nếu dùng code của ndu bài trên, có thể làm được nếu thêm 1 msgbox hỏi "tiếp không?" để lần lượt làm từng mảng.
PHP:
Sub Test()
Dim Rng As Range, TempRng As Range, Des As Range, StDes
  Dim i As Long, j As Long, k As Long
  On Error GoTo Thoat
  Set Rng = Application.InputBox("Chon vung du lieu nguon", Type:=8)
  Set StDes = Application.InputBox("Chon vung dat ket qua", Type:=8)
  For i = 1 To Rng.Areas.Count
    k = 0
    With Rng.Areas(i)
      For j = 1 To .Columns.Count
       Set TempRng = .Offset(, j - 1).Resize(, 1)
       Set Des = StDes.Offset((i - 1), k * TempRng.Count).Resize(, TempRng.Count)
       Des.Value = WorksheetFunction.Transpose(TempRng)
       k = k + 1
      Next j
    End With
  Next i
Tiep = MsgBox("Tiep?", vbYesNo)
    If Tiep = vbYes Then
    Test
    Else
    Exit Sub
End If
Thoat:   Exit Sub
End Sub

Đang định nói về chuỵên lỡ người dùng nhấn cancel thì... ndu đã thêm GoTo Thoat rồi.
 
Upvote 0
Tham gia thêm 1 cách dùng Find Method. Có dùng bài của RollOver79
PHP:
Sub ChangeRng()
Dim MyRng As Range, iL As Long, lCount As Long, RngFound As Range
[A1].Select
Set MyRng = Application.InputBox("Chon vung du lieu nguon", Type:=8)
Set STDes = Application.InputBox("Chon vung dat ket qua", Type:=8)
lCount = MyRng.Count
With MyRng
    Set RngFound = MyRng(1)
    STDes.Value = RngFound
    For iL = 1 To lCount - 1
    Set RngFound = .Find(What:="*", after:=RngFound, LookIn:=xlFormulas, LookAt _
        :=xlPart, SearchOrder:=xlByColumns)
        STDes.Offset(, iL) = RngFound
    Next
End With
If MsgBox("Tiep tuc nua chu?", vbYesNo) = vbYes Then ChangeRng
End Sub
Có 1 cái chưa biết là nếu rỗng thì nó bỏ qua.
Xin chỉ giáo.
 
Upvote 0
Tham gia thêm 1 cách dùng Find Method. Có dùng bài của RollOver79
PHP:
Sub ChangeRng()
Dim MyRng As Range, iL As Long, lCount As Long, RngFound As Range
[A1].Select
Set MyRng = Application.InputBox("Chon vung du lieu nguon", Type:=8)
Set STDes = Application.InputBox("Chon vung dat ket qua", Type:=8)
lCount = MyRng.Count
With MyRng
    Set RngFound = MyRng(1)
    STDes.Value = RngFound
    For iL = 1 To lCount - 1
    Set RngFound = .Find(What:="*", after:=RngFound, LookIn:=xlFormulas, LookAt _
        :=xlPart, SearchOrder:=xlByColumns)
        STDes.Offset(, iL) = RngFound
    Next
End With
If MsgBox("Tiep tuc nua chu?", vbYesNo) = vbYes Then ChangeRng
End Sub
Có 1 cái chưa biết là nếu rỗng thì nó bỏ qua.
Xin chỉ giáo.
Dử liệu loại khác và yêu cầu khác thì tôi không dám nói, nhưng ở trường hợp này e rằng FIND không thể nhanh hơn TRANSPOSE rồi
 
Upvote 0
Cho em được hỏi dùng Code gì để kiểm tra mảng một mảng bất kỳ để biết nó là mảng ngang hay mảng dọc, mảng 1 chiều hay là 2 chiều?

Xin cho em một ví dụ ah, em xin cảm ơn
 
Upvote 0
Cho em được hỏi dùng Code gì để kiểm tra mảng một mảng bất kỳ để biết nó là mảng ngang hay mảng dọc, mảng 1 chiều hay là 2 chiều?

Xin cho em một ví dụ ah, em xin cảm ơn

Đã là mảng thì không có vụ DỌC NGANG gì cả mà chỉ tính nó mấy chiều thôi (1 chiều, 2 chiều, 3 chiều,... vân vân...)
Để tính số chiều của 1 Array, có thể dùng UDF này:
PHP:
Function Dimensions(ByVal sArray) As Long
  Dim chkDim As Long, lCount As Long, tmpArr
  On Error Resume Next
  tmpArr = sArray
  If IsArray(tmpArr) Then
    Do While Err.Number = 0
      lCount = lCount + 1
      chkDim = LBound(tmpArr, lCount)
    Loop
   Dimensions = lCount - 1
  End If
End Function
Thí nghiệm hàm trên xem sao:
PHP:
Sub Test()
  Dim sArray
  sArray = Range("A1:C10")
  MsgBox Dimensions(sArray)
  sArray = Array(1, 2, 3)
  MsgBox Dimensions(sArray)
  sArray = Range("N1")
  MsgBox Dimensions(sArray)
End Sub
 
Upvote 0
Nếu vậy thì vẩn như em nói ở trên, em thêm vòng lập duyệt qua các Areas như sau:
PHP:
Option Explicit
Sub Test()
  Dim Rng As Range, TempRng As Range, Des As Range, StDes
  Dim i As Long, j As Long, k As Long
  On Error GoTo Thoat
  Set Rng = Application.InputBox("Chon vung du lieu nguon", Type:=8)
  Set StDes = Application.InputBox("Chon vung dat ket qua", Type:=8)
  For i = 1 To Rng.Areas.Count
    k = 0
    With Rng.Areas(i)
      For j = 1 To .Columns.Count
       Set TempRng = .Offset(, j - 1).Resize(, 1)
       Set Des = StDes.Offset((i - 1), k * TempRng.Count).Resize(, TempRng.Count)
       Des.Value = WorksheetFunction.Transpose(TempRng)
       k = k + 1
      Next j
    End With
  Next i
Thoat:   Exit Sub
End Sub
Có thể chuyển thoải mái nhiều mãng 2 chiều thành 1 chiều và đặt vùng kết quả sang bất cứ sheet nào
Các anh chị cho e hỏi là e muốn chuyển mảng 2 chiều thành mảng 1 chiều dưới dạng cột dọc và bỏ qua những giá trị trống ở mảng hai chiều thì phải sửa code ở trên như thế nào ạ?
 
Upvote 0
Mọi người cho em hỏi là em muốn chuyển mảng:
1 2 3 4
5 6 7 8
9 10 11 12
thành dạng một chiều như thế này:
1 5 9 10 6 2 3 7 11 12 8 4
thì phải làm như thế nào ạ?
Mong được các anh chị chỉ giáo
 
Upvote 0
Mọi người cho em hỏi là em muốn chuyển mảng:
1 2 3 4
5 6 7 8
9 10 11 12
thành dạng một chiều như thế này:
1 5 9 10 6 2 3 7 11 12 8 4
thì phải làm như thế nào ạ?
Mong được các anh chị chỉ giáo
Mã:
Dim arr, KQ(), i as long, j as long, k as long, z as long, n as long
'arr=mảng ban đầu
n=ubound(arr,1):z=ubound(arr,2)
redim KQ(1 to n*z)
For k=1 to z
   For j=1 to n
      i=i+1: KQ(i)=arr(j,k)
next j
next k
'Kết thúc
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom