Tạo dãy số ngẫu nhiên không trùng

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,905
Trên diển đàn GPE đã có rất nhiều bài viết nói về vấn đề này!
Tôi cũng đã tham khảo rất nhiều code ở các trang nước ngoài nhưng thấy rằng hầu hết đều viết rất khó hiểu và dài dòng!
Trong 1 dịp tình cờ khi nghiên cứu về Dictionary Object, tôi nhận thấy rằng nó có khả năng làm được điều này mà code lại cực kỳ đơn giản
Thuật toán dựa vào định nghĩa của Dictionary có đoạn: Key là những phần tử duy nhất trong Keys
Tôi đã xây dựng code như sau:
PHP:
Function UniqueRandomNum(Bottom As Long, Top As Long, Amount As Long)
  'Application.Volatile '<--- Neu muon gia tri thay doi khi bam F9
  On Error Resume Next
  If Amount > Top - Bottom + 1 Then Amount = Top - Bottom + 1
  With CreateObject("Scripting.Dictionary")
    Do
      .Add Int(Rnd() * (Top - Bottom + 1)) + Bottom, ""
    Loop Until .Count = Amount
    UniqueRandomNum = WorksheetFunction.Transpose(.Keys)
  End With
End Function
Cú pháp hàm:
PHP:
=UniqueRandomNum(Số nhỏ, Số lớn, bao nhiêu số cần tạo)
Giả sử các bạn muốn tạo ra 30 số ngẩu nhiên không trùng nằm trong khoảng từ 1 đến 100, các bạn làm như sau:
- Quét chọn 30 cell tùy ý theo chiều dọc, chẳng hạn là A1:A30
- Gõ vào thanh Formula công thức =UniqueRandomNum(1,100,30)
- Bấm tổ hợp phím Ctrl + Shift + Enter
Hãy thí nghiệm với đoạn Test sau:
PHP:
Sub Test()
  Range("A1:A30").Value = UniqueRandomNum(1, 100, 30)
End Sub
--------------
Ghi chú: Dictionary Object còn làm được nhiều thứ khác nữa, chẳng hạn có thể xây dựng hàm trích lọc các phần tử duy nhất (ngẫu nhiên và duy nhất đã làm được, đương nhiên duy nhất sẽ càng dể hơn)
 

File đính kèm

  • GetUniqueRandNum.xls
    24 KB · Đọc: 4,047
Lần chỉnh sửa cuối:
Upvote 0
nếu 20 số đó từ máy tính cho trong 100 số trên, phần tử của tập hợp là 20 số. có liên quan nhau không?
nếu xảy ra 10 lần như trên, tìm tập hợp liên quan? (mỗi lần có 20 phần tử tập hợp, 10 lần có 10x20 số (sẽ có số trùng nhau). tìm xác suất liên quan?

Bạn nên dùng hàm Draw (bác siwtom lập) tại , cho chuẩn hơn:
http://www.giaiphapexcel.com/forum/...thức-tính-một-dạng-Tổ-hợp&p=408551#post408551

còn việc
nếu xảy ra 10 lần như trên, tìm tập hợp liên quan? (mỗi lần có 20 phần tử tập hợp, 10 lần có 10x20 số (sẽ có số trùng nhau). tìm xác suất liên quan?

Bạn phải tự làm thui, vì có ai hiểu bạn nói gì đâu, vậy nhé
 
Upvote 0
cần giúp lọc ra ngẫu nhiên các dòng có tổng là một hàng số(ví dụ 20) và sắp xếp lên đầu
những dòng không thỏa mãn điều kiện có tổng là hằng số 20 thì đẩy xuống dưới cùng
cụ thể như file đính kèm
xin cảm ơn
 

File đính kèm

  • giuptoi.xlsx
    13 KB · Đọc: 23
Upvote 0
nếu muốn lấy thêm 3 số lẻ thì sao các pro
 

File đính kèm

  • tao day so ngau nhien.xlsx
    8.1 KB · Đọc: 48
Upvote 0
Tình cờ vào đây đọc, thấy các anh tranh luận hay quá nhưng không biết đến bao giờ Thắng mới hiểu được những vấn đề mà các anh tranh luận, có vẻ như đang học lớp 1 mà lại xem kiến thức lớp 12 vậy.
 
Upvote 0
Trên diển đàn GPE đã có rất nhiều bài viết nói về vấn đề này!
Tôi cũng đã tham khảo rất nhiều code ở các trang nước ngoài nhưng thấy rằng hầu hết đều viết rất khó hiểu và dài dòng!
Trong 1 dịp tình cờ khi nghiên cứu về Dictionary Object, tôi nhận thấy rằng nó có khả năng làm được điều này mà code lại cực kỳ đơn giản
Thuật toán dựa vào định nghĩa của Dictionary có đoạn: Key là những phần tử duy nhất trong Keys
Tôi đã xây dựng code như sau:
PHP:
Function UniqueRandomNum(Bottom As Long, Top As Long, Amount As Long)
  'Application.Volatile '<--- Neu muon gia tri thay doi khi bam F9
  On Error Resume Next
  If Amount > Top - Bottom + 1 Then Amount = Top - Bottom + 1
  With CreateObject("Scripting.Dictionary")
    Do
      .Add Int(Rnd() * (Top - Bottom + 1)) + Bottom, ""
    Loop Until .Count = Amount
    UniqueRandomNum = WorksheetFunction.Transpose(.Keys)
  End With
End Function
Cú pháp hàm:
PHP:
=UniqueRandomNum(Số nhỏ, Số lớn, bao nhiêu số cần tạo)
Giả sử các bạn muốn tạo ra 30 số ngẩu nhiên không trùng nằm trong khoảng từ 1 đến 100, các bạn làm như sau:
- Quét chọn 30 cell tùy ý theo chiều dọc, chẳng hạn là A1:A30
- Gõ vào thanh Formula công thức =UniqueRandomNum(1,100,30)
- Bấm tổ hợp phím Ctrl + Shift + Enter
Hãy thí nghiệm với đoạn Test sau:
PHP:
Sub Test()
  Range("A1:A30").Value = UniqueRandomNum(1, 100, 30)
End Sub
--------------
Ghi chú: Dictionary Object còn làm được nhiều thứ khác nữa, chẳng hạn có thể xây dựng hàm trích lọc các phần tử duy nhất (ngẫu nhiên và duy nhất đã làm được, đương nhiên duy nhất sẽ càng dể hơn)
Bác cho em hỏi chút,
Nếu bây giờ hàm của bác em không muốn dùng công thức mảng mà tạo số ngẫu nhiên trong khoảng đã cho và không trùng theo kiểu copy công thức từ ô A1 đến ô A30 thì như thế nào? Cảm ơn bác!
 
Upvote 0
Mình muốn tạo ra dãy số ngẫu nhiên không trùng nhau như này nhưng theo hàng ngang; mong mọi người giúp đỡ
 
Upvote 0
1. (Top - Bottom + 1) là 1 số ko thay đổi trong vòng lặp, để giảm tính toán nên đặt nó vào 1 biến tạm thời trước khi vào vào lặp.
2. "Scripting.Dictionary" là 1 COM, về giải thuật thì chắc chả có gì, nhưng nó đc viết trong C++, đã đc biên dịch ra mã máy tính rồi nên nó chạy nhanh lắm, dù các bác có giải thuật tốt trong vba thì về tốc độ chắc cũng ko lại đc với nó đâu.
 
Upvote 0
Upvote 0
Tôi muốn ứng dụng cái
Function UniqueRandomNum
vô Word. Đã chép code vô word rồi.
Nhưng khi gặp
WorksheetFunction.Transpose
thì chương trình chịu. Vì tất nhiên nó là word nên không biết
WorksheetFunction
Có cách nào để vẫn dùng được hàm này trên Word??

Cảm ơn
 
Upvote 0
cái này mà thầy tuấn cải tiến thêm cho nó ngẫu nhiên vừa có số, vừa có chuỗi luôn thì hay quá
 
Upvote 0
tôi muốn ứng dụng cái
function uniquerandomnum
vô word. đã chép code vô word rồi.
Nhưng khi gặp
worksheetfunction.transpose
thì chương trình chịu. Vì tất nhiên nó là word nên không biết
worksheetfunction
có cách nào để vẫn dùng được hàm này trên word??

Cảm ơn
cái này thì phải insert excel vào trong word thì code chạy bình thường như trên excel thôi
tôi có ví dụ đây
 

File đính kèm

  • Doc1.docx
    38.5 KB · Đọc: 36
Upvote 0
Cảm ơn Lê Duy Thương.

Cái hay của file excel nhúng trong word với tôi lại là không cần xóa nội dung trong vùng được chép đến của filter Advance.

Sheet1.Range("A4:G81").AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=Range("E1:E2"), CopyToRange:=Range("A4:G4"), Unique:=False


Mọi nội dung ở dưới Range("A4:G4") (cho đến tận hàng cuối cùng) đều bị xóa, dù số hàng chép vô không nhiều.

Và tôi đã thử với file excel . Vẫn đúng. Kể cả chép kết quả vô cùng sheet có dữ liệu được lọc.

Có thể đây là thuộc tính của Excel. Có thể nó sẽ hữu ích cho mọi người
 
Upvote 0
cảm ơn lê duy thương.

Cái hay của file excel nhúng trong word với tôi lại là không cần xóa nội dung trong vùng được chép đến của filter advance.

Sheet1.range("a4:g81").advancedfilter action:=xlfiltercopy, _
criteriarange:=range("e1:e2"), copytorange:=range("a4:g4"), unique:=false


mọi nội dung ở dưới range("a4:g4") (cho đến tận hàng cuối cùng) đều bị xóa, dù số hàng chép vô không nhiều.

Và tôi đã thử với file excel . Vẫn đúng. Kể cả chép kết quả vô cùng sheet có dữ liệu được lọc.

Có thể đây là thuộc tính của excel. Có thể nó sẽ hữu ích cho mọi người
Cái CHIÊU insert excel vào word này tôi đã học được từ khi mới học tin học. Học lóm thôi. Lúc đó công thức và vba tôi mù tịt--=0--=0
 
Upvote 0
Bài 56 tôi có hỏi dùng hàm UniqueRandomNum trong word
Nội dung đã được sửa như sau (chữ đỏ in đậm và nghiêng là tôi sửa)
Function UniqueRandomNum(Bottom As Long, Top As Long, Amount As Long) As String
On Error Resume Next
If Amount > Top - Bottom + 1 Then Amount = Top - Bottom + 1
With CreateObject
("Scripting.Dictionary")
Do
.
Add Int(Rnd() * (Top - Bottom + 1)) + Bottom, ""
Loop Until .Count = Amount
UniqueRandomNum = Join(.Keys)

'Bỏ UniqueRandomNum = WorksheetFunction.Transpose(.Keys)
End With
End
Function

Do word cũng có 2 hàm Join và Split nên tôi chuyển array thành xâu
UniqueRandomNum = Join(.Keys)
Trong chương trình "mẹ" ta dùng lệnh gán
xx = Split(
UniqueRandomNum ) (xx phải là biến kiểu Variable). Sau đó dùng xx bình thường.

Nêu ra đây để thấy vấn đề đã giải quyết.

Tuy nhiên, tôi không thể nào gán trực tiếp vô biến để không cần vòng vo như trên (dù rằng không dài dòng lắm). Mong sự góp ý của các bạn.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài 56 tôi có hỏi dùng hàm UniqueRandomNum trong word
Nội dung đã được sửa như sau (chữ đỏ in đậm và nghiêng là tôi sửa)
Function UniqueRandomNum(Bottom As Long, Top As Long, Amount As Long) As String
On Error Resume Next
If Amount > Top - Bottom + 1 Then Amount = Top - Bottom + 1
With CreateObject
("Scripting.Dictionary")
Do
.
Add Int(Rnd() * (Top - Bottom + 1)) + Bottom, ""
Loop Until .Count = Amount
UniqueRandomNum = Join(.Keys)

'Bỏ UniqueRandomNum = WorksheetFunction.Transpose(.Keys)
End With
End
Function

Do word cũng có 2 hàm Join và Split nên tôi chuyển array thành xâu
UniqueRandomNum = Join(.Keys)
Trong chương trình "mẹ" ta dùng lệnh gán
xx = Split(
UniqueRandomNum ) (xx phải là biến kiểu Variable). Sau đó dùng xx bình thường.

Nêu ra đây để thấy vấn đề đã giải quyết.

Tuy nhiên, tôi không thể nào gán trực tiếp vô biến để không cần vòng vo như trên (dù rằng không dài dòng lắm). Mong sự góp ý của các bạn.

ở đây chưa nói đến chuyện giải thuật chọn Random (giải thuật dùng On error kết hợp .Add là quá dở )
Có những cái khó hiểu mà chắc tại tôi chưa biết gì về Word nên thấy khó hiểu ?
hàm .Keys của Dic đã trả về 1 mảng 1 chiều rồi , tại sao phải

Mã:
[B][I]UniqueRandomNum = Join(.Keys)[/I][/B]
rồi ở dưới lại
Mã:
[COLOR=#000000][COLOR=#000000]xx = Split([/COLOR][/COLOR][B][I]UniqueRandomNum[/I][COLOR=#000000] )[/COLOR][/B]

tại sao không là
Mã:
[B][I]UniqueRandomNum = .Keys[/I][/B]
ở dưới
Mã:
[COLOR=#000000][COLOR=#000000]xx =[/COLOR][/COLOR][B][I]UniqueRandomNum[/I][/B]

xin cho biết lý do ?
 
Upvote 0

...
UniqueRandomNum = Join(.Keys)


<1> 'Bỏ UniqueRandomNum = WorksheetFunction.Transpose(.Keys)
End With
End
Function

<2> Do word cũng có 2 hàm Join và Split nên tôi chuyển array thành xâu
UniqueRandomNum = Join(.Keys)
Trong chương trình "mẹ" ta dùng lệnh gán
<3> xx = Split(UniqueRandomNum ) (xx phải là biến kiểu Variable). Sau đó dùng xx bình thường.

Nêu ra đây để thấy vấn đề đã giải quyết.

<4> Tuy nhiên, tôi không thể nào gán trực tiếp vô biến để không cần vòng vo như trên (dù rằng không dài dòng lắm). Mong sự góp ý của các bạn.

Chi tiết:
<1> Worksheetfunction là một object của Excel. Đương nhiên nếu file Word khong có nói vào Excel thì khong thể gọi object này.

<2> Hàm Join và Split là hàm của VBA nói chung. Khong phải của Word, Excel, hay Access gì cả

<3> Trong từ ngữ lập trình, variable có nghĩa là biến. Variance mới là kiểu biến động.

<4> gán trực tiếp vô biến có nghĩa là sao? Nếu muón hàm trả về môt mảng thì cứ việc cho nó là As Variant
 
Upvote 0
Chi tiết:
<1> Worksheetfunction là một object của Excel. Đương nhiên nếu file Word khong có nói vào Excel thì khong thể gọi object này.

<2> Hàm Join và Split là hàm của VBA nói chung. Khong phải của Word, Excel, hay Access gì cả

<3> Trong từ ngữ lập trình, variable có nghĩa là biến. Variance mới là kiểu biến động.

<4> gán trực tiếp vô biến có nghĩa là sao? Nếu muón hàm trả về môt mảng thì cứ việc cho nó là As Variant

Chính xác phải là

<2> Hàm Join và Split là hàm của VBA nói chung tức là của Word, Excel, hay Access.
<3> Variant mới là kiểu biến động. Như ví dụ sau (đã chạy thử), biến a có thể nhận mọi kiểu dữ liệu

Option Explicit
Sub vidu()
Dim a As Variant
a = "dfgh"
a = 1
a = Array(1, 3, 5)
End Sub

Do biến kiểu này thường bỏ qua phần "As Variant" nên nhiều khi kg cần nhớ chính xác

<4> Tôi đang thử gán trực tiếp. Nếu được sẽ comment sau

Cảm ơn VetMini
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom