Board logo

標題: [發問] 運動會競賽道次隨機分組 [打印本頁]

作者: ymes    時間: 2023-2-6 11:15     標題: 運動會競賽道次隨機分組

在下出現一個問題,希望大家能幫;忙:

100M比賽中,一共九個班級,每班二個人參加,想隨機分成三組,每組六人,現情況是:

一、同班不能分在同一組別

二、每班的人不能分在同一道次

麻煩請大家能予以協助,感謝!
作者: Andy2483    時間: 2023-2-7 09:28

回復 1# ymes


    謝謝前輩發表此主題與範例
後學學習後建議方案如下,請前輩試試看

[attach]35793[/attach]

執行前:
[attach]35794[/attach]

執行1:
[attach]35795[/attach]

執行2:
[attach]35796[/attach]

Option Explicit
Sub TEST_1()
Dim Arr, Brr, Crr, Y, 亂數&, 人數&, 道數&, 組數&, 項數&, 跑道數&, i&
Arr = Range([報名表!B2], [報名表!A65536].End(3))
人數 = UBound(Arr): 跑道數 = 6: ReDim Brr(跑道數 - 1, 1)
Head:
Set Y = CreateObject("Scripting.Dictionary")
Do While 項數 < 人數
   Randomize: 亂數 = Rnd() * 10000 Mod 人數 + 1
   If Y.Exists(亂數) = Empty Then
      項數 = 項數 + 1
      Y(亂數) = ""
      道數 = 項數 Mod 跑道數
      Y(Arr(亂數, 1) & "|" & 道數) = ""
      組數 = IIf(道數, 項數 \ 跑道數 + 1, 項數 \ 跑道數)
      Y(Arr(亂數, 1) & "/" & 組數) = ""
      Crr = Y(組數 & "/組")
      If Not IsArray(Crr) Then
         Crr = Brr
      End If
      道數 = IIf(道數, 道數, 跑道數)
      Crr(道數 - 1, 0) = Arr(亂數, 1): Crr(道數 - 1, 1) = Arr(亂數, 2)
      Y(組數 & "/組") = Crr
   End If
   If (Y.Count - 組數) Mod 項數 Then
      組數 = 0
      項數 = 0
      GoTo Head
   End If
Loop
With Sheets("分組表")
   For i = 1 To 組數
      .[B3].Item((i - 1) * 9 + 1, 1).Resize(跑道數, 2) = Y(i & "/組")
   Next
End With
Set Arr = Nothing
Set Brr = Nothing
Set Crr = Nothing
Set Y = Nothing
End Sub
作者: ymes    時間: 2023-2-8 02:11

回復 2# Andy2483


您太客氣了,測試了一陣子,可以用,而且非常符合在下需求,但……

巨集真的不熟,日後真的要修改比較困難,借問一下:

一、若跑道為八個跑道,要如何修改呢?

二、若有其他競賽項目也要隨機分組,又要如何修改呢?

可以的話,再勞煩幫忙想一下,感謝!
作者: Andy2483    時間: 2023-2-8 09:45

本帖最後由 Andy2483 於 2023-2-8 09:52 編輯

回復 3# ymes


    謝謝前輩回復
修改方案如下,請前輩試試看

[attach]35799[/attach]

執行前:
[attach]35802[/attach]

執行結果:
[attach]35801[/attach]


Option Explicit
Sub TEST_1()
Dim Drr, Brr, Crr, Y, 亂數&, 人數&, 道數&, 組數&, 執行數&, 跑道數&, i&
Dim 項目$, Arr(1 To 1000, 1 To 3), n&, m&
項目 = Split(ActiveSheet.Name, "(")(0)
跑道數 = [A3].End(xlDown).Row - 2
Drr = Range([報名表!C2], [報名表!A65536].End(3))
For i = 1 To UBound(Drr)
   If Drr(i, 3) Like 項目 & "*" Then
      n = n + 1
      Arr(n, 1) = Drr(i, 1): Arr(n, 2) = Drr(i, 2): Arr(n, 3) = Drr(i, 3)
   End If
   If InStr(Cells(i, 1), 項目) Then Cells(i, 2).Resize(1, 2).ClearContents: m = m + 1
Next
If n = 0 Or m < n Then MsgBox "無法執行": Exit Sub
[L:N].ClearContents: [L1].Resize(n, 3) = Arr
人數 = n: ReDim Brr(跑道數 - 1, 1)
Head:
Set Y = CreateObject("Scripting.Dictionary")
Do While 執行數 < 人數
   Randomize: 亂數 = Rnd() * 10000 Mod 人數 + 1
   If Y.Exists(亂數) = Empty Then
      執行數 = 執行數 + 1
      Y(亂數) = ""
      道數 = 執行數 Mod 跑道數
      Y(Arr(亂數, 1) & "|" & 道數) = ""
      組數 = IIf(道數, 執行數 \ 跑道數 + 1, 執行數 \ 跑道數)
      Y(Arr(亂數, 1) & "/" & 組數) = ""
      Crr = Y(組數 & "/組")
      If Not IsArray(Crr) Then
         Crr = Brr
      End If
      道數 = IIf(道數, 道數, 跑道數)
      Crr(道數 - 1, 0) = Arr(亂數, 1): Crr(道數 - 1, 1) = Arr(亂數, 2)
      Y(組數 & "/組") = Crr
   End If
   If (Y.Count - 組數) Mod 執行數 Then
      組數 = 0
      執行數 = 0
      GoTo Head
   End If
Loop
For i = 1 To 組數
   [B3].Item((i - 1) * (跑道數 + 3) + 1, 1).Resize(跑道數, 2) = Y(i & "/組")
Next
End Sub
Sub 清除()
Dim 項目$, i&
項目 = Split(ActiveSheet.Name, "(")(0)
For i = 1 To [報名表!A65536].End(3)
   If InStr(Cells(i, 1), 項目) Then Cells(i, 2).Resize(1, 2).ClearContents
Next
[L:N].ClearContents
End Sub
作者: ymes    時間: 2023-2-8 15:04

再次感謝,但很抱歉,在下對巨集一籌莫展,讓我過份一點,再問一些問題:

一、如果要新增其他項目(如200M、800M……甚至是男生組),要怎麼改參數呢?

二、報名表是總表,如果要改成二年級的學生檢錄表,又要怎麼改呢?

再次提問,希望能給予解答,感激不盡
作者: Andy2483    時間: 2023-2-8 16:36

本帖最後由 Andy2483 於 2023-2-8 16:45 編輯

回復 5# ymes


    二年級項目每班參加人數 4 人 !可以放寬同一組同一班兩人參賽嗎?

一年級範例再試試看:
[attach]35806[/attach]

PS:各年級建議分開儲存
作者: ymes    時間: 2023-2-8 22:08

本帖最後由 ymes 於 2023-2-8 22:15 編輯

回復 6# Andy2483


是我搞錯了,100M項目沒設定到,每班單項仍然是二人為限

請問:

如果要增設項目,要在哪裡改參數呀?

譬如說新增個男生1600M或女生1600M的項目,要在哪處修改呢?

=============================================
試了一下,原來增加新的分頁,就可以,我再試試,非常感謝您!
作者: Andy2483    時間: 2023-2-9 08:55

本帖最後由 Andy2483 於 2023-2-9 08:56 編輯

回復 7# ymes


    謝謝前輩再回復
1.後學複習了一下,做了註解,請前輩參考
2.如果跑道數,每班人數,同班不同道這些條件導致隨機組合無解!! 該如何設計才能判定無解?? 並跳出 "無解" 提視窗後結束程序??
例如:每班人數4人會導致無解,請前輩們指導,謝謝


Option Explicit
Sub TEST_1()
Dim Drr, Brr, Crr, Y, 亂數&, 人數&, 道數&, 組數&, 執行數&, 跑道數&, i&
Dim 項目$, Arr(1 To 1000, 1 To 3), n&, m&
'↑宣告變數:(Drr, Brr, Crr, Y)是通用型變數,項目 是字串變數,Arr是二維陣列,
'其他是長整數變數

項目 = Split(ActiveSheet.Name, "(")(0)
'↑令 項目 這字串變數是 以"("符號 將工作表名分割成一維陣列取0索引號的字串
跑道數 = [A3].End(xlDown).Row - 2
'↑令 (跑道數) 這長整數變數是 從[A3]儲存格往下找到空格的前一格列號 - 2
Drr = Range([報名表!C2], [報名表!A65536].End(3))
'↑令 Drr這通用型變數 是二維陣列,以報名表[C2]到A欄最後一個有內容儲存格值倒入
For i = 1 To UBound(Drr)
'↑設順迴圈!從1到 Drr陣列縱向最後索引號
   If Drr(i, 3) Like 項目 & "*" Then
   '↑如果i迴圈數第3欄Drr陣列值是 (項目)變數 開頭的字串??
      n = n + 1
      '↑令n這長整數變數 累加1
      Arr(n, 1) = Drr(i, 1): Arr(n, 2) = Drr(i, 2): Arr(n, 3) = Drr(i, 3)
      '↑令n變數列第1欄Arr陣列值是 i變數列第1欄Drr陣列值,~~依此類推
   End If
   If InStr(Cells(i, 1), 項目) Then Cells(i, 2).Resize(1, 2).ClearContents: m = m + 1
   '↑如果工作表i變數列第1欄儲存格值 包含了(項目)變數字串!就清除右側兩儲存格的內容,
   '令m這長整數變數累加1

Next
If n = 0 Then
'↑如果n變數是 0?
   MsgBox "沒有名單!無法執行": Exit Sub
   '↑跳出提示窗~"沒有名單!無法執行"~,之後結束程式執行
End If
If m < n Then
'↑如果 m變數小於 n變數?
   MsgBox "組數表格不夠!無法執行": Exit Sub
   '↑跳出提示窗~"組數表格不夠!無法執行"~,之後結束程式執行
End If
[L:N].ClearContents: [L1].Resize(n, 3) = Arr
'↑令[L:N]這3欄儲存格內容清除 :令[L1]擴展向下n變數列,向右擴展3欄的範圍儲存格以Arr陣列值倒入
人數 = n: ReDim Brr(跑道數 - 1, 1)
'↑令 人數這長整數變數是 n變數值: 宣告Brr陣列大小(縱向從0到 跑道數-1,橫向從0到 1)
Head:
Set Y = CreateObject("Scripting.Dictionary")
'↑令Y是 字典
Do While 執行數 < 人數
'↑設條件迴圈:當 (執行數)變數 < (人數)變數!就繼續執行!
   Randomize: 亂數 = Rnd() * 10000 Mod 人數 + 1
   '↑令 亂數這長整數變數是 1 到 (人數)變數的Rnd()亂數值
   If Y.Exists(亂數) = Empty Then
   '↑如果產生的(亂數)變數值沒有在Y字典裡?
      執行數 = 執行數 + 1
     '↑令(執行數)這長整數變數 累加1
      Y(亂數) = ""
      '↑令(亂數)變數當key,item是空字元放入Y字典
      道數 = 執行數 Mod 跑道數
      '↑令(道數)這長整數變數是 (執行數) 除 (跑道數) 的餘數
      Y(Arr(亂數, 1) & "|" & 道數) = ""
      '↑令(亂數)變數列第1欄Arr陣列值 連接 "|" 再連接 (道數)變數的組合字串當key,item是空字元放入Y字典
      組數 = IIf(道數, 執行數 \ 跑道數 + 1, 執行數 \ 跑道數)
      '↑令(組數)這長整數變數是 以IIf()判斷的回傳值,
      '如果(道數)變數不是0,就令(組數)變數是 (執行數)變數 除 (跑道數)的商取整數後 + 1
      '如果(道數)變數是0,就令(組數)變數是 (執行數)變數 除 (跑道數)的商取整數

      Y(Arr(亂數, 1) & "/" & 組數) = ""
      '↑令(亂數)列第1欄Arr陣列值 連接 "/" 再連接 (組數)變數的組合字串當key,item是空字元放入Y字典
      Crr = Y(組數 & "/組")
      '↑令Crr這通用型變數是 以(組數)變數 連接 "/組"成的組合字串當key,查Y字典得到的item
      If Not IsArray(Crr) Then
      '↑如果Crr變數不是陣列?
         Crr = Brr
         '↑令Crr 是 Brr陣列
      End If
      道數 = IIf(道數, 道數, 跑道數)
      '↑令(道數)變數是 以IIf()判斷的回傳值,
      '如果(道數)變數不是0!就令(道數)變數是 (道數)變數
      '如果(道數)變數是0!就令(道數)變數是 (跑道數)變數

      Crr(道數 - 1, 0) = Arr(亂數, 1): Crr(道數 - 1, 1) = Arr(亂數, 2)
      '↑令(道數)變數-1索引號列第0索引號欄Crr陣列值是 (亂數)變數列第1欄Arr陣列值
      '↑令(道數)變數-1索引號列第1索引號欄Crr陣列值是 (亂數)變數列第2欄Arr陣列值

      Y(組數 & "/組") = Crr
      '↑令以(組數)變數連接 "/組" 的組合字串當key,item是 Crr陣列,放入Y字典
      '如果該key已存在Y陣列!就取代其item

   End If
   If (Y.Count - 組數) Mod 執行數 Then
   '↑如果(Y字典key數量 - (組數)變數) 除 (執行數)變數的餘數不是0?
      組數 = 0
      '↑令(組數)變數是 0
      執行數 = 0
      '↑令(執行數)變數是 0
      GoTo Head
      '↑跳到 Head標示處繼續執行
   End If
Loop
'↑跳到 Do 位置繼續執行
For i = 1 To 組數
'↑設順迴圈!i從1到 (組數)變數
   [B3].Item((i - 1) * (跑道數 + 3) + 1, 1).Resize(跑道數, 2) = Y(i & "/組")
   '↑[B3]儲存格擴展向下(跑道數)變數列,向右擴展2欄範圍儲存格以 陣列值 倒入,
   '陣列值是:以 i迴圈數 連接 "/組"的組合字串當key,查Y字典得到的item

Next
End Sub
作者: ymes    時間: 2023-2-9 15:23

回復 8# Andy2483

非常感謝您旳幫忙,目前正研讀寶典,並稍微修改中,

如果……如果再發問,會不會太過份呀……

一、若每班可報名三人參加單項競賽,雖也會跑出正確結果,但似乎會跑較久,但仍會輸出正確結果(有時四、五秒,有時二十秒左右)

二、分組抬頭女生60M想改成60M女生,卻出現錯誤,偵錯時這段話變成黃色底色:Cells(i, 2).Resize(1, 2).ClearContents,應如何修正呢?

最後,再次感謝您的幫忙,讓在下能較順利完成檢錄工作{:3_59:} {:3_59:} {:3_59:}
作者: Andy2483    時間: 2023-2-9 16:27

回復 9# ymes


    如果……如果再發問,會不會太過份呀……
謝謝前輩繼續發問,給後學繼續學習

一、若每班可報名三人參加單項競賽,雖也會跑出正確結果,但似乎會跑較久,但仍會輸出正確結果(有時四、五秒,有時二十秒左右)
機率的問題:每班3人,不同組,不同道 的組合比較少,論壇很多厲害的前輩或許看到可以幫我們一把,提升效率,謝謝各位前輩

二、分組抬頭女生60M想改成60M女生,卻出現錯誤,偵錯時這段話變成黃色底色:Cells(i, 2).Resize(1, 2).ClearContents,應如何修正呢?
請前輩上傳此產生錯誤的範例
作者: ymes    時間: 2023-2-9 16:51

本帖最後由 ymes 於 2023-2-9 16:57 編輯

範例如下:

========================
呃……改成這樣後,變成沒有名單,無法執行,之前是我眼花嗎……

======================================
有時會出現偵錯,有時會出現沒有名單,無法執行
作者: Andy2483    時間: 2023-2-10 07:13

本帖最後由 Andy2483 於 2023-2-10 07:15 編輯

回復 11# ymes


    前輩早安
101:一年一班
102:一年二班
~
201:二年一班
202:二年二班
~
~
501:五年一班

不是這規則嗎?
現在的範例與#5樓的範例有衝突
實際的年級班級是什麼規則?
作者: ymes    時間: 2023-2-10 08:39

本帖最後由 ymes 於 2023-2-10 08:42 編輯

回復 12# Andy2483


不好意思,造成您困擾了,

學校報名系統跑出來資訊是一年一班、一年二班……

一、剛試了一下,改成以上樣式,60M會出現錯誤訊息,但100M是會跑出正確結果
[attach]35811[/attach]

二、原表格標題為女子100M,但改成100M女生後,會出現下圖錯誤(是我太吹毛求疵,但想說為符合競賽項目…)
[attach]35812[/attach]
作者: Andy2483    時間: 2023-2-10 09:38

本帖最後由 Andy2483 於 2023-2-10 09:49 編輯

回復 13# ymes


    謝謝前輩繼續一起學習做研討回覆
設雙條件隨機名單不等於公平,表格陸續增減修改不會困擾,都只能選擇接受
修改需求如下,請前輩繼續測試需求,自己修改看看,謝謝

[attach]35813[/attach]

執行前:         ps:清除後的表格若是8跑道數,就算8道名單:若刪除剩6跑到,即算6跑道名單,隨意增減
[attach]35814[/attach]

執行結果:
[attach]35815[/attach]
  1. Option Explicit
  2. Dim 組表格 As Range, R&, C%
  3. Sub 開始分組()
  4. Dim Drr, Brr, Crr, Y, 亂數&, 人數&, 道數&, 組數&, 執行數&, 跑道數&, i&
  5. Dim 項目$, Arr(1 To 1000, 1 To 3), n&, m&, 組別, xR As Range
  6. 項目 = Split(ActiveSheet.Name, "(")(0)
  7. 跑道數 = [A2].End(xlDown).Row - 2
  8. Drr = Range([報名表!C2], [報名表!A65536].End(3))
  9. For i = 1 To UBound(Drr)
  10.    If Drr(i, 3) Like 項目 & "*" Then
  11.       n = n + 1
  12.       Arr(n, 1) = Drr(i, 1): Arr(n, 2) = Drr(i, 2): Arr(n, 3) = Drr(i, 3)
  13.    End If
  14. Next
  15. If n = 0 Then
  16.    MsgBox "沒有名單!無法執行": Exit Sub
  17. End If
  18. If 跑道數 < 1 Then
  19.    MsgBox "跑道數不符合規則!無法執行": Exit Sub
  20. End If
  21. Call 清除: [L1].Resize(n, 3) = Arr
  22. 人數 = n: ReDim Brr(跑道數 - 1, 1)
  23. Head:
  24. Set Y = CreateObject("Scripting.Dictionary")
  25. Do While 執行數 < 人數
  26.    Randomize: 亂數 = Rnd() * 10000 Mod 人數 + 1
  27.    If Y.Exists(亂數) = Empty Then
  28.       執行數 = 執行數 + 1
  29.       Y(亂數) = ""
  30.       道數 = 執行數 Mod 跑道數
  31.       Y(Arr(亂數, 1) & "|" & 道數) = ""
  32.       組數 = IIf(道數, 執行數 \ 跑道數 + 1, 執行數 \ 跑道數)
  33.       Y(Arr(亂數, 1) & "/" & 組數) = ""
  34.       Crr = Y(組數 & "/組")
  35.       If Not IsArray(Crr) Then Crr = Brr
  36.       道數 = IIf(道數, 道數, 跑道數)
  37.       Crr(道數 - 1, 0) = Arr(亂數, 1): Crr(道數 - 1, 1) = Arr(亂數, 2)
  38.       Y(組數 & "/組") = Crr
  39.    End If
  40.    If (Y.Count - 組數) Mod 執行數 Then 組數 = 0: 執行數 = 0: GoTo Head
  41. Loop
  42. For i = 1 To 組數 - 1: 組表格.Copy Cells(i * (R + 1) + 1, 1): Next
  43. For i = 1 To 組數
  44.    組別 = "(第" & Application.Text(i, "[DBNum1]0") & "組)"
  45.    Set xR = [B3].Item((i - 1) * (跑道數 + 3) + 1, 1)
  46.    xR.Resize(跑道數, 2) = Y(i & "/組")
  47.    Set xR = xR.Item(-1, 0)
  48.    xR.Value = Split(xR.Value, "(")(0) & 組別
  49. Next
  50. End Sub
  51. Sub 清除()
  52. Dim uR&
  53. R = [A2].End(xlDown).Row
  54. C = [A2].End(xlToRight).Column
  55. uR = ActiveSheet.UsedRange.Rows.Count
  56. [L:N].ClearContents
  57. [A2].End(xlDown).Item(2, 1).Resize(uR - R, C).Clear
  58. [B3].Resize(R - 2, 2).ClearContents
  59. Set 組表格 = Range([A1], Cells(R, C))
  60. End Sub
複製代碼

作者: ymes    時間: 2023-2-10 13:13

本帖最後由 ymes 於 2023-2-10 13:16 編輯

回復 14# Andy2483

感謝您幫忙不斷改進,讓表單能朝自己所期望的目標邁進,能再問一下嗎?

下圖中G3儲存格中先行設定:G3=IF(F3<>0,RANK(F3,$F$3:$F$10,1),""),在分組後希望G14能自動生成為:G14=IF(F14<>0,RANK(F14,$F$14:$F$21,1),"")

希望能再次幫忙,感謝!
作者: Andy2483    時間: 2023-2-10 14:32

本帖最後由 Andy2483 於 2023-2-10 14:42 編輯

回復 15# ymes


    謝謝前輩,後學黔驢技窮了,請前輩們指導
不知前輩改動多少程式碼?

請將下列紅字新增或取代, 或 上傳前輩最新範例

Option Explicit
Dim 組表格 As Range, R&, C%
Sub 開始分組()
Dim Drr, Brr, Crr, Y, 亂數&, 人數&, 道數&, 組數&, 執行數&, 跑道數&, i&
Dim 項目$, Arr(1 To 1000, 1 To 3), n&, 組別, xR As Range
項目 = Split(ActiveSheet.Name, "(")(0)
跑道數 = [A2].End(xlDown).Row - 2
Drr = Range([報名表!C2], [報名表!A65536].End(3))
For i = 1 To UBound(Drr)
   If Drr(i, 3) Like 項目 & "*" Then
      n = n + 1
      Arr(n, 1) = Drr(i, 1): Arr(n, 2) = Drr(i, 2): Arr(n, 3) = Drr(i, 3)
   End If
Next
If n = 0 Then
   MsgBox "沒有名單!無法執行": Exit Sub
End If
If 跑道數 < 1 Then
   MsgBox "跑道數不符合規則!無法執行": Exit Sub
End If
Call 清除: [L1].Resize(n, 3) = Arr
人數 = n: ReDim Brr(跑道數 - 1, 1)
Head:
Set Y = CreateObject("Scripting.Dictionary")
Do While 執行數 < 人數
   Randomize: 亂數 = Rnd() * 10000 Mod 人數 + 1
   If Y.Exists(亂數) = Empty Then
      執行數 = 執行數 + 1
      Y(亂數) = ""
      道數 = 執行數 Mod 跑道數
      Y(Arr(亂數, 1) & "|" & 道數) = ""
      組數 = IIf(道數, 執行數 \ 跑道數 + 1, 執行數 \ 跑道數)
      Y(Arr(亂數, 1) & "/" & 組數) = ""
      Crr = Y(組數 & "/組")
      If Not IsArray(Crr) Then Crr = Brr
      道數 = IIf(道數, 道數, 跑道數)
      Crr(道數 - 1, 0) = Arr(亂數, 1): Crr(道數 - 1, 1) = Arr(亂數, 2)
      Y(組數 & "/組") = Crr
   End If
   If (Y.Count - 組數) Mod 執行數 Then 組數 = 0: 執行數 = 0: GoTo Head
Loop
'For i = 1 To 組數 - 1: 組表格.Copy Cells(i * (R + 1) + 1, 1): Next '這行點掉,新增下列紅字
Dim S$, T&
For i = 1 To 組數 - 1
   組表格.Copy Cells(i * (R + 1) + 1, 1)
   T = 3 + ((R + 1) * i)
   S = "=IF(F" & T & "<>0,RANK(F" & T & ",$F$" & T & ":$F$" & T + 跑道數 - 1 & ",1),"""")"
   Cells(i * (R + 1) + 1, 1).Item(3, 7).Resize(跑道數, 1) = S
Next

For i = 1 To 組數
   組別 = "(第" & Application.Text(i, "[DBNum1]0") & "組)"
   Set xR = [B3].Item((i - 1) * (跑道數 + 3) + 1, 1)
   xR.Resize(跑道數, 2) = Y(i & "/組")
   Set xR = xR.Item(-1, 0)
   xR.Value = Split(xR.Value, "(")(0) & 組別
Next
End Sub
Sub 清除()
Dim uR&
R = [A2].End(xlDown).Row
C = [A2].End(xlToRight).Column
uR = ActiveSheet.UsedRange.Rows.Count
[L:N].ClearContents
[A2].End(xlDown).Item(2, 1).Resize(uR - R, C).Clear
[B3].Resize(R - 2, 2).ClearContents
'新增下列紅字
[F3].Resize(R - 2, 1).ClearContents
[G3].Resize(R - 2, 1) = "=IF(F3<>0,RANK(F3,$F$3:$F$" & R & ",1),"""")"

Set 組表格 = Range([A1], Cells(R, C))
End Sub
作者: 准提部林    時間: 2023-2-10 15:30

本帖最後由 准提部林 於 2023-2-10 15:56 編輯

公式+排序+vba//
[attach]35820[/attach]

若未出結果..再試幾次..若都試不出來, 可能資料結構無法做出分組(同一班不能同道, 是道關卡)~~

__更正:最後一組可能未滿人數, 道次會有誤差, 以空格填入
      最後一組人數不足時, 不會由1~?順序排列, 會有間隔

作者: Andy2483    時間: 2023-2-10 15:59

回復 17# 准提部林


    謝謝前輩指導,後學研究一下
作者: 准提部林    時間: 2023-2-10 18:43

改下//最後一組無間隔//
[attach]35821[/attach]
作者: ymes    時間: 2023-2-10 22:48

回復 16# Andy2483


不好意思,因為真的不懂vba,所以可能動了些自以為是的地方,可能讓您困擾,說聲抱歉了!

雖然  准提部林大大說用公式+vba可解決以下困擾,但還想說問問看:

一、原本A:C欄分別為班級、姓名、項目,想改成取A:D欄,分別為項目、班級、姓名、學號,要怎麼改動呢?

二、可以做個分組鈕,讓一鍵完成隨機分組嗎?這樣就不用到各分頁一一去按分組鈕了

三、各單項競賽L:N欄原本有驗證資訊,可以像 准提部林大大般,加上分配的組別及道次嗎?

再次衷心感謝您的幫忙!
作者: ymes    時間: 2023-2-10 23:08

回復 19# 准提部林


    謝謝您提供另一個想法,vba真的不會,但看到vba這麼方便,都懶得寫公式了……
作者: Andy2483    時間: 2023-2-11 08:30

本帖最後由 Andy2483 於 2023-2-11 08:38 編輯

回復 21# ymes


    謝謝前輩繼續一起學習

1.後學想法不一樣:公式是VBA智慧的精華濃縮,是後學學習EXCEL的里程碑,建議莫忽視公式
2.前輩感受到VBA的好處,以後常上論壇一起學習,讓更多事可以事半功倍
3.前輩陸續增加項目與規則,想必最終版本未定案,以往為同事設計複雜點的表格都要開會討論,
討論各方提出的意見,做出最後的定案
4.後學的經驗是程式寧願寫大一點廣一點,後續做小修改,如果條件像前輩的情境一直變更,程式常常要大改或打掉重寫,
常常改條件對學習中的後學是很好的學習機會,常常變思維,磨耐心,謝謝前輩
5.如果前輩的需求是很急迫的!建議前輩先找可最終定案的團隊一起討論出最終版本,論壇裡很多厲害的前輩可以指導
6.如果需求不急!陸續再提出不同需求討論學習也是很好的方式
7.後學拋磚引玉,,可以得到前輩們的指導,最大的意義是希望更多人一起學習

謝謝論壇,謝謝各位前輩
作者: Andy2483    時間: 2023-2-11 09:22

回復 21# ymes


    謝謝 准提部林前輩指導,謝謝前輩一起學習
以下是片段學習心得註解,先提供給前輩參考
此段心得重點在於:用同一陣列濾出符合條件的資料,精確的將資料放入目標儲存格中

Option Explicit
Sub A_載入資料()
Dim Arr, TC$, T$, i&, N&
'↑宣告變數!Arr是通用型變數,(TC,T)是字串變數,(i,N)是長整數變數
Call C_清除
'↑執行(C_清除)副程式
TC = [k2]
'↑令TC這字串變數是 [k2]儲存格值
If TC = "" Then MsgBox "*未輸入項目名稱! ": Exit Sub
'↑如果TC變數是 空字元!就跳出提視窗~~,按確認後即結束程式執行
Application.ScreenUpdating = False
'↑令螢幕暫不隨程式執行作變化
Arr = Range([報名表!c1], [報名表!a65536].End(3))
'↑令Arr這通用型變數是二維陣列,以"報名表"工作表[C1]到A欄最後一個有內容儲存格,
'這範圍儲存格值倒入陣列中

For i = 2 To UBound(Arr)
'↑設順迴圈!i從2到Arr陣列縱向最大索引列號
    If Arr(i, 3) = TC Then
    '↑如果i迴圈列第3欄Arr陣列值是 TC變數??
       N = N + 1
       '↑令這N長整數變數累加 1
       Arr(N, 1) = Arr(i, 1)
       '↑令N變數列第1欄Arr陣列值是 i迴圈列第1欄Arr陣列值
       Arr(N, 2) = Arr(i, 2)
       '↑令N變數列第2欄Arr陣列值是 i迴圈列第2欄Arr陣列值
    End If
Next i
If N = 0 Then MsgBox "*沒有符合項目資料! ": Exit Sub
'↑如果N變數是 0!就跳出提示窗~~,按確認後即結束程式執行
[m2].Resize(N, 4).Value = Arr
'↑令[m2]擴展向下N變數列,向右4欄的範圍儲存格值以Arr陣列值倒入
Call 重置資料
'↑執行(重置資料)副程式
End Sub
作者: 准提部林    時間: 2023-2-11 10:01

回復 20# ymes


一、原本A:C欄分別為班級、姓名、項目,想改成取A:D欄,分別為項目、班級、姓名、學號,要怎麼改動呢?
__看來這還是草槁版本, 一般學號會放在姓名前面吧!  
__項目名稱的"男生/女生"固定放後面? 且只有賽跑項目?
__最好給完整"定案版", 論壇給的是解決方案而不是代工, 自己要能自行更改程式的

二、可以做個分組鈕,讓一鍵完成隨機分組嗎?這樣就不用到各分頁一一去按分組鈕了
__一次各分頁自動完成是可以, 但必須自己要先建立所需分表, 並輸入必要的參數
__各分表都要再次人工檢查驗證正確性, 那麼個別單頁執行也沒啥差別(反正單頁執行並不太花時間)

三、各單項競賽L:N欄原本有驗證資訊,可以像 准提部林大大般,加上分配的組別及道次嗎?
__L:N欄"原本"有驗證資訊---附件沒有看到那"原本"資料??? 那來的?

公式+VBA+工作表基本操作.....有時更有利於表格的製作及處理, 不能偏廢!!!
作者: Andy2483    時間: 2023-2-11 10:22

回復 19# 准提部林


    謝謝前輩
以下心得註解請前輩再指導,謝謝

Sub 重置資料()
Dim R&
'↑宣告變數!R是長整數變數
R = [m65536].End(3).Row
'↑令R這長整數變數是 M欄最後一個有內容儲存格列號
If R < 2 Then Exit Sub
'↑令如果R變數 < 2 !就結束程式執行
Application.ScreenUpdating = False
'↑令螢幕暫不隨程式執行作變化
With Range("m2:p" & R)
'↑以下是關於[M2]到 P欄第 R變數列,這範圍儲存格的程序
     .Columns(3) = "=IF(M2="""",999,COUNTIF(M$1:M2,M2))"
     '↑令這範圍內相對欄位的第3欄(O欄)值是 (公式)字串
     '公式:如果M2是空字元的條件成立,就顯示 999,
     '否則就計算M欄前幾列裡 有幾個(當列M欄相同字串)

     .Sort Key1:=.Item(3), Order1:=xlAscending, Header:=xlNo
     '↑令資料以O欄做沒有標題列的順排序
     .Columns(3) = ""
     '↑令這範圍內相對欄位的第3欄(O欄)值是 空字元
     .Columns(4) = "=INT((ROW(A1)-1)/K$3)+1"
     '↑令這範圍內相對欄位的第4欄(P欄)值是 (公式)字串,
     '公式:前一列號減1後除以[K3]儲存格值,再去除小數轉化為整數,最後+1
     '用前一列號除的意義是:不會整除,就不必擔心整除不加 1的問題,謝謝前輩

     .Columns(4) = .Columns(4).Value
     '↑令這範圍內相對欄位的第4欄(P欄)值是 自身公式計算值
End With
End Sub
作者: Andy2483    時間: 2023-2-11 12:05

回復 19# 准提部林


    謝謝前輩指導,後學駑鈍,這太難了
後學程度只能大概知道程式碼意思,其邏輯意義太難了,後學繼續學習,希望有天能開竅看懂

Sub B_開始分組()
Dim Arr, xD, R&, N&, i&, T$, TC$, TV$, X%, V%, Nx%, j%
'↑宣告變數!(Arr,xD)是通用型變數,(R,N,i)是長整數變數,(T,TC,TV)是字串變數,其他是短整數變數
[k6] = ""
'↑令[K6]儲存格值是空字元
Call 重置資料
'↑執行(重置資料)副程式
R = [m65536].End(3).Row
'↑令R這長整數變數是 M欄最後一個有內容儲存格列號
If R < 2 Then MsgBox "*尚未載入資料! ": Exit Sub
'↑如果R變數 < 2 !就跳出提示窗~~,按確認後即結束程式執行
Set xD = CreateObject("Scripting.Dictionary")
'↑令xD是 字典
Re_Try:
'↑程序位置識別
Nx = Nx + 1
'↑令Nx這短整數變數累加 1
If Nx > 10 Then MsgBox "*執行分組多次無結果!請重試或檢查資料是否正確! ": Exit Sub
'↑如果Nx變數 > 10!就跳出提視窗~~,按確認後即結束程式執行
xD.removeall
'↑令xD字典清空
TC = Left(123456789, [k3])
'↑令TC這字串變數是 123456789字串的左側 [k3]值個字
For j = 1 To [k5] - 1: xD(j) = TC: Next
'↑設順迴圈j從1到 [k3]值(跑道數)-1 :令以j變數當key,item是 TC變數,納入 xD字典裡
xD(j) = Left(TC, [k4] - ([k5] - 1) * [k3])
'↑令j變數當key,item是 TC變數左側的 [k4] - ([k5] - 1) * [k3]個字
'=人數 - (組數 - 1)乘上 跑道數

Randomize
'↑不固定亂數初始值
Arr = Range("m2:p" & R)
'↑令Arr這通用型變數是二維陣列,以[M2]到 P欄第 R變數列範圍,
'這範圍儲存格值倒入陣列中

For i = R - 1 To 1 Step -1
'↑設逆迴圈i從 R變數-1 到1 ,令每次迴圈讓i -1
    T = Arr(i, 1)
    '↑令T這字串變數是 i變數列第1欄Arr陣列值
    N = 0
    '↑令N這長整數變數是 0
    V = Arr(i, 4)
    '↑令V這短整數變數是 i變數列第4欄Arr陣列值
    TV = xD(V)
    '↑令TV這字串變數是 以V變數當key查xD字典回傳的item值
    Do
    '↑設無限迴圈! 需要想辦法跳出迴圈!
       X = Val(Mid(TV, Int(Rnd * Len(TV)) + 1, 1))
       '↑令X這短整數變數是 Val函式回傳的數字,
       '函式內容:TV變數從 Int(Rnd * Len(TV)) + 1 個字開始,取1個字
       '亂數 乘 TV變數的字元數後,去除小數,最後 +1

       If xD(T & "/" & X) = 0 Then Exit Do
       '↑如果以 T變數連接 "/" 符號再連接 X變數當key查 xD字典回傳item值是 0??
       '如果是 0,就跳出迴圈

       N = N + 1
       '↑令N變數累加 1
       If N >= 200000 Then GoTo Re_Try
       '↑如果N變數 N >= 200000!,就跳到 Re_Try標示位置繼續執行
    Loop
    xD(V) = Replace(TV, X, "")
    '↑令以V變數當key,item是(TV變數 將X變數以空字元置換)後的字串,納入xD字典
    xD(T & "/" & X) = 1
    '↑令以T變數連接 "/" 再連接 X變數的新字串當key,item是 1,納入xD字典
    Arr(i, 3) = X
    '↑令i迴圈列第3欄Arr陣列值是 X變數
Next i
With [m2].Resize(R - 1, 4)
'↑以下是[M2]擴展向下 R - 1列,向右 4欄範圍儲存格的程序
     .Value = Arr
     '↑令這範圍儲存格值以Arr陣列值倒入
     .Sort Key1:=.Item(4), Order1:=xlAscending, _
           Key2:=.Item(3), Order2:=xlAscending, Header:=xlNo
     '↑令資料以P欄做沒有標題列的順排序,同時做第二層O欄順排序
End With
Application.ScreenUpdating = True: [k6] = "OK"
'↑令螢幕恢復變化: 令[k6] 儲存格值是 "OK" 字串
MsgBox "∼分組完成∼ "
'↑跳出提示窗~~
End Sub
作者: 准提部林    時間: 2023-2-11 13:09

回復 26# Andy2483

以下是"思路"解析///
TC = Left(123456789, [k3])  '以跑道數取數字串...跑道有6--道次字串= 123456, 有8則= 12345678
For j = 1 To [k5] - 1: xD(j) = TC: Next '各組都預先置入道次字串
xD(j) = Left(TC, [k4] - ([k5] - 1) * [k3]) '最後一組...若只有4人...則置入 1234

V = Arr(i, 4): TV = xD(V)  ' 取出各組的道次字串(它經過亂數取數後, 會有變化...字元數遞減)

For i = R - 1 To 1 Step -1 '反向迴圈...讓最後一組優先佔用1 ~ ? 跑道, 才不會有間隔

X = Val(Mid(TV, Int(Rnd * Len(TV)) + 1, 1))  '隨機從該組"道次字串"中取出一個數字
If xD(T & "/" & X) = 0 Then Exit Do '以[班級+道次]檢查, 等於0...表示該班級尚未佔用該跑道..合格..跳出//否則重新取數

xD(V) = Replace(TV, X, "") '此次取出的道次數字...須從道次字串中剔除...下次就不會有這個數字(字串每跑一次, 減少一個數)
xD(T & "/" & X) = 1  '[班級&道次]記數為1, 表示該班級已佔用了該跑道(下次排除用)


===========================
作者: Andy2483    時間: 2023-2-11 13:27

回復 27# 准提部林


    謝謝前輩的思路解析指導,後學努力測試領悟中,謝謝前輩提攜
作者: ymes    時間: 2023-2-11 19:37

謝謝二位大神幫忙,其實在第八樓就已經解決在下問題了,
實在是不會修改VBA,所以就不斷發問,
想藉由小部份修改看出日後可能改動的地方,
殊不知造成欲解決者的困擾,真的很抱歉,
再跟網路上幫忙的人說聲感謝,有了您們熱心的幫忙,讓我能順利完成表單,感謝!
作者: ymes    時間: 2023-2-11 19:55

回復 24# 准提部林


謝謝大大的提醒,日後以自己熟悉的公式為主,

做自己懂的事也較安全,感謝!
作者: Andy2483    時間: 2023-2-13 10:20

回復 29# ymes


    謝謝前輩回復
1.學無止盡,雖然有點被前輩耍的感覺,後學甘之如飴,罰前輩繼續發表其他主題給後學們做學習
2. 准提部林前輩的高深回答,後學也還一知半解,請前輩常上論壇一起學習
作者: ymes    時間: 2023-2-15 22:40

回復 31# Andy2483


抱歉,是真的不會修改vba,所以後續想說請幫忙改動一些小地方,

希望日後有更動時,可以自行修改,

沒想到變成您的困擾……sorry

不過,後續靠著您的幫忙及公式,已完成多項競賽表單,再次說聲感謝!:lol :lol :lol
作者: Andy2483    時間: 2023-2-16 07:03

回復 32# ymes


    恭喜前輩推展順利
請前輩常發表新主題,以弭補對後學的傷害,謝謝前輩
一起學習
作者: Andy2483    時間: 2023-2-17 09:55

本帖最後由 Andy2483 於 2023-2-17 10:02 編輯

回復 32# ymes
回復 19# 准提部林


    再次謝謝前輩發表此主題,謝謝 准提部林前輩指導
後學學習公式的心得,請前輩參考指導,謝謝

[attach]35851[/attach]




歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)