Ngày tháng bị đảo ngược trong dictionary (1 người xem)

Liên hệ QC

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

Anhduong2015

Thành viên chính thức
Tham gia
29/7/21
Bài viết
53
Được thích
12
Nhờ anh/chị giúp đỡ cụ thể: khi em xuất dữ liệu Dictionary nếu không dùng Tranpose thì hiện ngày/tháng/năm bình thường nhưng khi dùng Tranpose để dữ liệu hiển thị trong một cột thì hiển thị sai định dạng ngày tháng
Do kiến thức hạn hẹp cám ơn mọi sự giúp đỡ hoặc gợi ý ạ.
Help.jpg
 

File đính kèm

Lần chỉnh sửa cuối:
Không liên quan gì chỗ nào khác.

Dính chưởng ở ngay đây này:

1650858979467.png

1/ Lần sau chụp hình thì chụp phun không che toàn màn hình để biết cái DateTime của máy tính là gì.
2/ Gửi file và code lên, chứ ảnh đẹp chỉ ngắm thôi.
 
Không liên quan gì chỗ nào khác.

Dính chưởng ở ngay đây này:

View attachment 274969

1/ Lần sau chụp hình thì chụp phun không che toàn màn hình để biết cái DateTime của máy tính là gì.
2/ Gửi file và code lên, chứ ảnh đẹp chỉ ngắm thôi.
Không phải chỗ Cdate đó anh ạ vì chỗ đó em đã Comment Block rồi.
Em test thử thì không có Transpose đổ ra dòng thì ra đúng mà thêm Transpose để chuyển qua cột thì không ra dạng Date.
Em có đính kèm lại file #1 rồi ạ. mong anh xem giúp
 

Đoán đúng luôn.
Dùng User form thì đừng có bao giờ dùng CDate() mà phải dùng DateSerial().
Nhiều bài nói cái này rồi.

Bằng chứng là ngày tháng ghi từ Form xuống bảng tính là ăn chuỗi chứ có phải DateTime xịn đâu. Nhìn E13 trở xuống đó.

1650870612435.png

1650870496683.png


* Thêm một cái nữa. Dữ liệu Number, DateTime đừng có canh lề, cứ để mặc định nhảy về bên phải của Cell. Để nhìn một phát là biết dữ liệu có đúng chuẩn không.
 
Đoán đúng luôn.
Dùng User form thì đừng có bao giờ dùng CDate() mà phải dùng DateSerial().
Nhiều bài nói cái này rồi.

Bằng chứng là ngày tháng ghi từ Form xuống bảng tính là ăn chuỗi chứ có phải DateTime xịn đâu. Nhìn E13 trở xuống đó.

View attachment 274988

View attachment 274987


* Thêm một cái nữa. Dữ liệu Number, DateTime đừng có canh lề, cứ để mặc định nhảy về bên phải của Cell. Để nhìn một phát là biết dữ liệu có đúng chuẩn không.
Không đúng nha anh. Cái này em dùng Sub trên Module s3_laytenngay không phải ghi từ Userform ạ.
 
Không đúng nha anh. Cái này em dùng Sub trên Module s3_laytenngay không phải ghi từ Userform ạ.

Tôi chỉ ra cái sai tận gốc rễ.

DateTime từ Form xuống bảng tính: Sai một phát nếu định dạng chuỗi DateTime đó khác thiết lập hệ thống.
DateTime lấy từ bảng tính lên mảng: Sai thêm một phát nữa nếu định dạng chuỗi DateTime đó khác thiết lập hệ thống.

Bạn từ từ tìm hiểu mà làm. Bí kíp, kỹ thuật tôi nêu hết rồi.

Đọc ----- thật ------ chậm ------ thôi.
 
Tôi chỉ ra cái sai tận gốc rễ.

DateTime từ Form xuống bảng tính: Sai một phát nếu định dạng chuỗi DateTime đó khác thiết lập hệ thống.
DateTime lấy từ bảng tính lên mảng: Sai thêm một phát nữa nếu định dạng chuỗi DateTime đó khác thiết lập hệ thống.

Bạn từ từ tìm hiểu mà làm. Bí kíp, kỹ thuật tôi nêu hết rồi.

Đọc ----- thật ------ chậm ------ thôi.
1. Đầu tiên cám ơn anh đã góp ý giúp em. Tuy nhiên trong trường hợp này thì cái gốc rễ không phải là ở điểm gán dữ liệu ngày tháng sử dụng Cdate từ Userform xuống Sheet vì em đã xóa trắng (Clear All) dữ liệu cột ngày tháng và nhập tay lại vẫn như cũ.
2. Vấn đề em thấy và đã chạy thực tế là khi sử dụng Application.WorksheetFunction.Transpose nó sẽ ra ngày tháng đảo ngược, ngược lại thì đúng.
 
1. Đầu tiên cám ơn anh đã góp ý giúp em. Tuy nhiên trong trường hợp này thì cái gốc rễ không phải là ở điểm gán dữ liệu ngày tháng sử dụng Cdate từ Userform xuống Sheet vì em đã xóa trắng (Clear All) dữ liệu cột ngày tháng và nhập tay lại vẫn như cũ.
2. Vấn đề em thấy và đã chạy thực tế là khi sử dụng Application.WorksheetFunction.Transpose nó sẽ ra ngày tháng đảo ngược, ngược lại thì đúng.
Đã kiểm tra thử thì đúng là sau khi transpose dic.keys ngày tháng bị đảo ngược. Mà lạ là nếu add key thông qua một biến long gán ngày tháng thì không lỗi, mà add trực tiếp thì lỗi.
Nguyên nhân thì không rõ, còn khắc phục thì add key ngày tháng bằng hàm Dateserial cho đảm bảo
File kiểm tra lỗi:
 

File đính kèm

Đã kiểm tra thử thì đúng là sau khi transpose dic.keys ngày tháng bị đảo ngược. Mà lạ là nếu add key thông qua một biến long gán ngày tháng thì không lỗi, mà add trực tiếp thì lỗi.
Nguyên nhân thì không rõ, còn khắc phục thì add key ngày tháng bằng hàm Dateserial cho đảm bảo
File kiểm tra lỗi:
Cám ơn bạn nhiều nhé, mình đã thêm một biến long vào thì kết quả đã ra đúng. mặc dù không rõ tại sao nhưng kết quả đúng yêu cầu là tuyệt vời.
 

File đính kèm

Không hề bị làm sao.
Vụ DateTime này mình nói rồi. Bạn để ý các bài của mình đều xử lý vậy.
Đúng là em cũng đọc nhiều bài và tìm hiểu thì Date Time nên dùng value2.
Nhưng vì sao thì thật tình cũng chưa tường tận lắm
Em cũng từng đọc qua bài này, có vẻ như họ khuyên nên dùng value2
1650881935122.png
Nhưng thắc mắc là tại sao trong nhiều bài code lại không dùng hẳn value2 (thấy hầu như value - trừ date time) , trong khi nó nhanh hơn và lấy giá trị chuẩn hơn???

https://stackoverflow.com/questions/17359835/what-is-the-difference-between-text-value-and-value2
 
Bill Gate luôn tạo ra những điều thú vị bất ngờ cho chúng ta xem. Kiểu long đã được đổi thành double, kiểu date thì lại thành string, Đây chính là điều mà chủ thớt này đã ngờ ngợ nhân ra. Sau khi chuyển về string, lúc viết xuống sheet thì excel lại can thiệt thêm một bước nữa gây ra kết quả khó đoán. Cái này chắc nhờ bạn nào viết cho cái hàm quay tay mới cho nhanh mà bảo đảm.


1650899932686.png
 
Nhân tiện các anh/ chị cho em hỏi thêm là trong câu lệnh: .Range("F10").Resize(, c2).Value = dic2.Keys làm sao để các kết quả cách nhau xen kẽ một cột. chỗ này hơi khó diễn tả anh/chị quan tâm xin vui lòng xem hình giúp em. Do cùng bài toán em sợ mở nhiều chủ đề không hay nên có gì không đúng mong anh/chị thông cảm giúp.
Xin cám ơn rất nhiều.
1.jpg

2.jpg
 

File đính kèm

Nhân tiện các anh/ chị cho em hỏi thêm là trong câu lệnh: .Range("F10").Resize(, c2).Value = dic2.Keys làm sao để các kết quả cách nhau xen kẽ một cột. chỗ này hơi khó diễn tả anh/chị quan tâm xin vui lòng xem hình giúp em. Do cùng bài toán em sợ mở nhiều chủ đề không hay nên có gì không đúng mong anh/chị thông cảm giúp.
Xin cám ơn rất nhiều.
View attachment 275008

View attachment 275009
Không biết ai làm thế nào chứ với tôi thì tôi sẽ dùng 1 vòng lặp duyệt qua hết keys lấy kết quả vào 1 mảng thì mới chen vị trí chứa giá trị rỗng vào được.
 
Không biết ai làm thế nào chứ với tôi thì tôi sẽ dùng 1 vòng lặp duyệt qua hết keys lấy kết quả vào 1 mảng thì mới chen vị trí chứa giá trị rỗng vào được.
Anh/chị có thể giúp em đoạn code lấy key từ dic ra được không? Em viết mà mãi không được ạ.
 
Không biết ai làm thế nào chứ với tôi thì tôi sẽ dùng 1 vòng lặp duyệt qua hết keys lấy kết quả vào 1 mảng thì mới chen vị trí chứa giá trị rỗng vào được.
Hiện tại em mới nghĩ ra được code chạy thủ công như thế này kết quả đúng nhưng nhìn hơi củ chuối xíu.
Capture.PNG
 
Không biết ai làm thế nào chứ với tôi thì tôi sẽ dùng 1 vòng lặp duyệt qua hết keys lấy kết quả vào 1 mảng thì mới chen vị trí chứa giá trị rỗng vào được.

Ở bước làm việc với Dictionary object, anh ghi luôn keys cần lấy vào một mảng là được.

Dim mangTieuDe as variant, chiso as long
''
Redim mangTieuDe( 1 to so_phan_tu_xet_nghiem * 2)
chiso=1
''
'Trong vòng lặp '
objDic.add skey, item
mangTieuDe(chiso) = skey
chiso = chiso + 2

'Ghi kết quả vào bảng tính'
If chiso> 0 then Target.resize(1, chiso).value = mangTieuDe
 
Hiện tại em mới nghĩ ra được code chạy thủ công như thế này kết quả đúng nhưng nhìn hơi củ chuối xíu.
View attachment 275020
Tạo riêng cho nó cái mảng. Đưa nó vào mảng ngay từ lúc add key. Nếu Dic chưa có gì thì add vào cột đầu trong mảng rồi cho biến cột tăng dần, khi dic đã tồn tại key thì tăng biến cột thêm 1 nữa rồi add vào mảng... nếu khó hiểu thì bỏ qua nha...
 
Ở bước làm việc với Dictionary object, anh ghi luôn keys cần lấy vào một mảng là được.

Dim mangTieuDe as variant, chiso as long
''
Redim mangTieuDe( 1 to so_phan_tu_xet_nghiem * 2)
chiso=1
''
'Trong vòng lặp '
objDic.add skey, item
mangTieuDe(chiso) = skey
chiso = chiso + 2

'Ghi kết quả vào bảng tính'
If chiso> 0 then Target.resize(1, chiso).value = mangTieuDe
Đúng rồi bạn. Đó là tôi quên thòng 1 câu là không can thiệp vào các dòng code đã có.
 
Ở bước làm việc với Dictionary object, anh ghi luôn keys cần lấy vào một mảng là được.

Dim mangTieuDe as variant, chiso as long
''
Redim mangTieuDe( 1 to so_phan_tu_xet_nghiem * 2)
chiso=1
''
'Trong vòng lặp '
objDic.add skey, item
mangTieuDe(chiso) = skey
chiso = chiso + 2

'Ghi kết quả vào bảng tính'
If chiso> 0 then Target.resize(1, chiso).value = mangTieuDe
Em làm như anh hướng dẫn nhưng nó chỉ ra được 1 kết quả nằm tuốt ở ngoài khơi luôn ạ, do chỗ so_phan_tu_xet_nghiem em không rõ biến nó là gì? mong anh giúp thêm ạ.
Capture.PNG
Bài đã được tự động gộp:

Tạo riêng cho nó cái mảng. Đưa nó vào mảng ngay từ lúc add key. Nếu Dic chưa có gì thì add vào cột đầu trong mảng rồi cho biến cột tăng dần, khi dic đã tồn tại key thì tăng biến cột thêm 1 nữa rồi add vào mảng... nếu khó hiểu thì bỏ qua nha...
Hihi. cao siêu quá em xin chịu ạ.
 

File đính kèm

Em làm như anh hướng dẫn nhưng nó chỉ ra được 1 kết quả nằm tuốt ở ngoài khơi luôn ạ, do chỗ so_phan_tu_xet_nghiem em không rõ biến nó là gì? mong anh giúp thêm ạ.
View attachment 275021
Bài đã được tự động gộp:


Hihi. cao siêu quá em xin chịu ạ.
Bạn làm đúng hết những gì mà bài #19 đã chỉ. Cái sai của bạn là redim mangTieuDe trong vòng lặp nên qua mỗi lần lặp là kết quả trong mangTieuDe bị reset và trống rỗng, chỉ có cái chiso là vẫn cứ tăng đều. Chỉ còn mỗi cái tiêu đề cuối là chấm dứt vòng lặp kia nên không bị reset.
 
Lần chỉnh sửa cuối:
Tạo riêng cho nó cái mảng. Đưa nó vào mảng ngay từ lúc add key. Nếu Dic chưa có gì thì add vào cột đầu trong mảng rồi cho biến cột tăng dần, khi dic đã tồn tại key thì tăng biến cột thêm 1 nữa rồi add vào mảng... nếu khó hiểu thì bỏ qua nha...
Đây là kỹ thuật đít sần với item gồm nhiều trường.
Thay vì phải ghép cả đống trường vào mỗi item thì tạo một mảng 2 chiều, chứa mỗi trường vào một cột. Item trong đít sần là chỉ số dòng của mảng.
Để thực hiện, cần tạo mảng 2 chiều với số dòng lớn nhất có thể, và số cột tối thiểu là 1. Cứ mỗi lần cần thêm cột để chứa trường mới thì dùng Redim Reserved để tăng số cột.

Đúng là em cũng đọc nhiều bài và tìm hiểu thì Date Time nên dùng value2.
Nhưng vì sao thì thật tình cũng chưa tường tận lắm
Em cũng từng đọc qua bài này, có vẻ như họ khuyên nên dùng value2
View attachment 274998
Nhưng thắc mắc là tại sao trong nhiều bài code lại không dùng hẳn value2 (thấy hầu như value - trừ date time) , trong khi nó nhanh hơn và lấy giá trị chuẩn hơn???

https://stackoverflow.com/questions/17359835/what-is-the-difference-between-text-value-and-value2
Value2 lấy kết quả chứa bên trong bảng tính. Value lấy kết quả theo kiểu dữ liệu mà Excel hiểu.
Do luật trên, Value2 sẽ lấy ngày thành số (Double); Value lấy ngày thành ngày (Date). Đương nhiên là số thì dễ làm việc hơn.
Vì vậy, nếu lấy ngày để tính toán thì nên dùng Value2.
Tuy nhiên nếu chép trở lại bảng tính thì Value2 sẽ chép lại dạng Double, và người viết code phải thêm phần chỉnh format cột thành dạng Date.
Tại sao dùng Value?:
1. lười, vì nó giản dị hơn.
2. người sử dụng có 100% tự tin về mức độ hiểu biết ngày tháng cũng như cách sử lý ngày tháng của mình. Tôi là 1 trong số đó.
- tôi rất ít khi dùng Value2 vì cả hai lý do trên, cộng thêm lý do:
-- tôi quan niệm tốc độ theo độ phức tạp code chứ không theo tiết lộ bên trong các hàm thư viện. Hiện nay, Microsoft đâu có nói họ lấy Value và Value2 bằng phương pháp gì. Người ta chỉ dựa theo kinh nghiệm và test để biết. Theo tinh thần gói kín code, MS không hề cho biết họ có dự định sửa code Value và Value2. Biết đâu trong tương lai, tốc độ truy cập hai thuộc tính này in hệt nhau? hay thậm chí, ngược lại?
 
Lần chỉnh sửa cuối:
Bạn làm đúng hết những gì mà bài #19 đã chỉ. Cái sai của bạn là redim mangTieuDe trong vòng lặp nên qua mỗi lần lặp là kết quả trong mangTieuDe bị reset và trống rỗng, chỉ có cái chiso là vẫn cứ tăng đều. Chỉ còn mỗi cái tiêu đề cuối là chấm dứt vòng lặp kia nên không bị reset.
Cám ơn anh/chị em đưa cái Redim lên trước vòng lặp đã ra kết quả đúng. Nhưng chỗ khai báo Redim mangTieuDe(1 to ?x2) em chưa rõ chỗ dấu ? là mình lồng biến gì vô? hiện e đang gõ đại là 100.
Xin cám ơn
 
Cám ơn anh/chị em đưa cái Redim lên trước vòng lặp đã ra kết quả đúng. Nhưng chỗ khai báo Redim mangTieuDe(1 to ?x2) em chưa rõ chỗ dấu ? là mình lồng biến gì vô? hiện e đang gõ đại là 100.
Xin cám ơn
Lúc đầu thì đâu biết kích thước cột của tiêu đề đâu nên cách đơn giản nhất là áng chừng và khai báo đại. Ví dụ ước cỡ 100 cột như bạn rồi x 2.

Còn không thì có cách khác: Redim ở trong vòng lặp tại vị trí như lúc trước:
Redim Preserve mangTieuDe(1 to chiso * 2)
 
Lúc đầu thì đâu biết kích thước cột của tiêu đề đâu nên cách đơn giản nhất là áng chừng và khai báo đại.

Không biết chính xác nhưng chắc chắn biết số lượng tối đa = so_phan_tu_xet_nghiem * 2

Còn không thì có cách khác: Redim ở trong vòng lặp tại vị trí như lúc trước:
Redim Preserve mangTieuDe(1 to chiso * 2)
Hết cách mới dùng Redim Preserve trong vòng lặp anh nhé, vì cái đó rất nặng nhọc.
 
Lúc đầu thì đâu biết kích thước cột của tiêu đề đâu nên cách đơn giản nhất là áng chừng và khai báo đại. Ví dụ ước cỡ 100 cột như bạn rồi x 2.

Còn không thì có cách khác: Redim ở trong vòng lặp tại vị trí như lúc trước:
Redim Preserve mangTieuDe(1 to chiso * 2)
Em lấy theo kích thước của mảng luôn Redim mangTieuDe(1 to Ubound(arr,1))
 
thử cách này xem.
Mã:
                ReDim mangTieuDe(1 To 1, 1 To 2 * dic2.Count) '1 cot an 2 cot
                Dim vTemp
                chiso = 0
                For Each vTemp In dic2.Keys()
                    chiso = chiso + 1 'Nhay toi vi tri de viet
                    mangTieuDe(1, chiso) = vTemp
                    chiso = chiso + 1 ' bo qua mot cot
                Next

1650961082594.png
 
Mảng trong VBA theo chế độ cột trọng dòng khinh. Tức là xếp theo cột.
Ví dụ mảng A(1 to 3, 1 to 5) thì trong bộ nhớ các phần tử được sắp theo A(1, 1), A(2, 1), A(3, 1), (A1, 2), A(2, 2), A(3, 2),...
Vì vậy, có thể khai báo cả đống cột rồi lúc chép xuống bảng tính đã có phương thức Resize của Range bảo đảm số cột. Khai như vậy cũng ít bị bộ nhớ có khảng trống giữa.
Khai cả đống dòng thì dễ bị bộ nhớ có khoảng trống lớn ở giữa nên cần cẩn thận hơn.
Thưc ra khoảng trống giữa hoàn toàn không liên quan gì đến kết quả. Chỉ là hơi chậm 1 chút thôi. Tức là nếu hệ thống có cache lớn thì có thể nhận thấy, hệ thống cache nhỏ thì truy cập hoàn toàn qua RAM nên sẽ không thấy khác. Chỉ khi nào RAM dỏm, phần firmware dịch địa chỉ yếu (từ số địa chỉ sang vùng trên stick) thì lại thấy khác. Lưu ý là ở đây tôi nói từ "hơi chậm" theo hoàn cảnh GPE, chứ chính quan niệm của tôi thì vài phần ngàn giây không kể là có khác biệt.
 
Lần chỉnh sửa cuối:
PHP:
Option Explicit
Sub s3_lay_ten_ngay() '20/4/2022 tu viet
    Application.ScreenUpdating = False
        Dim arr, cell As Range
        Dim lr&, i&, dk$, c&, c2&
        Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
        Dim dic2 As Object: Set dic2 = CreateObject("Scripting.Dictionary")
        dic2.CompareMode = TextCompare
        With Sheet2
            .AutoFilterMode = False
            lr = .Range("F" & Rows.Count).End(xlUp).Row
            arr = .Range("F9:M" & lr).Value2
            dk = .Range("P3").Value
        End With
        For i = 1 To UBound(arr)
            If arr(i, 6) = dk Then
                If Not dic.Exists(arr(i, 1)) Then
                    dic.Add arr(i, 1), ""
                End If
                If Not dic2.Exists(arr(i, 3)) Then
                    dic2.Add arr(i, 3), ""
                End If
            End If
        Next i
            c = dic.Count
            c2 = dic2.Count
            If c2 = 0 Then Exit Sub
            i = 0
            With Sheet3
                .Range(.Cells(10, 5), .Cells(10, 5 + c2)).EntireColumn.Hidden = False
                .Range(.Cells(10, 5), .Cells(10, 5 + c2)).ClearContents
                For Each cell In .Range("F10").Resize(, c2 * 2 - 1)
                    i = i + 1
                    If WorksheetFunction.IsOdd(i) Then cell.Value = dic2.Keys()(Int((i - 1) / 2))
                Next
                .Range(.Cells(11, 5), .Cells(11 + c, 5)).EntireRow.Hidden = False
                .Range("E11:E" & 10 + c).ClearContents
                .Range("E11").Resize(c).Value = Application.WorksheetFunction.Transpose(dic.Keys)
                .Range("E11:E" & 10 + c).Sort .Range("E10"), xlAscending
                .Range(.Cells(10, 6 + c2 * 2), .Cells(10, 52)).EntireColumn.Hidden = True
                .Range(.Cells(11 + c, 5), .Cells(400, 5)).EntireRow.Hidden = True
            End With
Application.ScreenUpdating = True
End Sub
 
PHP:
Option Explicit
Sub s3_lay_ten_ngay() '20/4/2022 tu viet
    Application.ScreenUpdating = False
        Dim arr, cell As Range
        Dim lr&, i&, dk$, c&, c2&
        Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
        Dim dic2 As Object: Set dic2 = CreateObject("Scripting.Dictionary")
        dic2.CompareMode = TextCompare
        With Sheet2
            .AutoFilterMode = False
            lr = .Range("F" & Rows.Count).End(xlUp).Row
            arr = .Range("F9:M" & lr).Value2
            dk = .Range("P3").Value
        End With
        For i = 1 To UBound(arr)
            If arr(i, 6) = dk Then
                If Not dic.Exists(arr(i, 1)) Then
                    dic.Add arr(i, 1), ""
                End If
                If Not dic2.Exists(arr(i, 3)) Then
                    dic2.Add arr(i, 3), ""
                End If
            End If
        Next i
            c = dic.Count
            c2 = dic2.Count
            If c2 = 0 Then Exit Sub
            i = 0
            With Sheet3
                .Range(.Cells(10, 5), .Cells(10, 5 + c2)).EntireColumn.Hidden = False
                .Range(.Cells(10, 5), .Cells(10, 5 + c2)).ClearContents
                For Each cell In .Range("F10").Resize(, c2 * 2 - 1)
                    i = i + 1
                    If WorksheetFunction.IsOdd(i) Then cell.Value = dic2.Keys()(Int((i - 1) / 2))
                Next
                .Range(.Cells(11, 5), .Cells(11 + c, 5)).EntireRow.Hidden = False
                .Range("E11:E" & 10 + c).ClearContents
                .Range("E11").Resize(c).Value = Application.WorksheetFunction.Transpose(dic.Keys)
                .Range("E11:E" & 10 + c).Sort .Range("E10"), xlAscending
                .Range(.Cells(10, 6 + c2 * 2), .Cells(10, 52)).EntireColumn.Hidden = True
                .Range(.Cells(11 + c, 5), .Cells(400, 5)).EntireRow.Hidden = True
            End With
Application.ScreenUpdating = True
End Sub
Cám ơn anh nhiều nhé.
 

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

Back
Top Bottom