excel VBA进行间比法设计

在品比试验大家多使用间比法试验设计,这里通过excel VBA实现间比法设计,代码如下:

vbscript 复制代码
Sub 生成试验设计()

Dim ws As Worksheet
Dim rng As Range, rng2 As Range, rng3 As Range
Dim cell As Range, lastcell As Range
Dim rd As String, sn As String, pl As String   'rd为是否随机排列品种顺序,sn即sheetname的简称,pl即排在sheet表中的方向的简称
Dim ck As String, var_num As Integer, pl2 As String, method As String    ' method即对照设置方法,var_num即对照间品种数量,pl2即品种在每排的排列方式
Dim row_num As Integer    '每排行数
Dim i As Integer, j As Integer, r As Integer, s As Integer, m As Integer, n As Integer, lastRow As Integer
Dim t_num As Integer, c_num As Integer, ck_num As Integer   't_num为加上对照后总的品种数,c_num为总列数
Dim arr As Variant, arr2 As Variant, rngValues As Variant, tmp As Variant
Dim arr5 As Variant, arr6 As Variant
Dim col_min As Integer, col_max As Integer, row_min As Integer, row_max As Integer

Application.ScreenUpdating = False       '刷新屏幕关闭
Application.DisplayAlerts = False        '警告提示框关闭



'获取初始设置
sn = Range("A2").Value    '新建工作表的名称
rd = Range("A5").Value   '是否随机排列品种顺序
pl = Range("A8").Value    '试验设计是横向排列还是纵向排列
row_num = Range("A11").Value    '每排行数
pl2 = Range("A14").Value    '品种在排之间的排列方式
method = Range("A17").Value  '对照的设置方法
var_num = Range("A20").Value  '对照间品种的间隔数
ck = Range("A23").Value    '设置对照名称,默认为"CK"



'获取品种名称
lastRow = Range("C10000").End(xlUp).Row    '获取品种名称列的最后一行的行号
Set rng = Range("C2:C" & lastRow)


' 将范围内的值存储在数组中
rngValues = rng.Value
ReDim arr(UBound(rngValues)) As Variant
arr = rngValues

' 随机排列数组中的元素
If rd = "是" Then
    Randomize ' 初始化随机数生成器
    For m = LBound(arr) To UBound(arr) - 1
        n = Int((UBound(arr) - m + 1) * Rnd + m)
        ' 交换元素
        tmp = arr(m, 1)
        arr(m, 1) = arr(n, 1)
        arr(n, 1) = tmp
    Next m
End If

If method = "逢X法" Then
    '确定包含对照的总品种数量
    t_num = lastRow - 1 + Int((lastRow - 1) / (var_num))

        
    '设置排区号的数组
    ReDim arr2(1 To t_num, 1 To 4) As Variant
    
    '确定排数,并将含有对照的品种名称列入新的数组中
    If t_num Mod row_num Then
        c_num = Int(t_num / row_num) + 1
        '将含有对照的品种信息列入新数组中
        r = 1
        s = 1
        For i = 1 To c_num - 1
            For j = 1 To row_num
                arr2(r, 1) = i
                arr2(r, 2) = j
                arr2(r, 3) = r
                If r Mod (var_num + 1) = 1 Then
                    arr2(r, 4) = ck
                    r = r + 1
                Else
                    arr2(r, 4) = arr(s, 1)
                    r = r + 1
                    s = s + 1
                End If
            Next
        Next
        
        For j = 1 To (t_num Mod row_num)
            arr2(r, 1) = c_num
            arr2(r, 2) = j
            arr2(r, 3) = r
            If r Mod (var_num + 1) = 1 Then
                arr2(r, 4) = ck
                r = r + 1
            Else
                arr2(r, 4) = arr(s, 1)
                r = r + 1
                s = s + 1
            End If
        Next
        
    Else
        c_num = Int(t_num / row_num)
        '将含有对照的品种信息列入新数组中
        r = 1
        s = 1
        For i = 1 To c_num
            For j = 1 To row_num
                arr2(r, 1) = i
                arr2(r, 2) = j
                arr2(r, 3) = r
                If r Mod 10 = 1 Then
                    arr2(r, 4) = ck
                    r = r + 1
                Else
                    arr2(r, 4) = arr(s, 1)
                    r = r + 1
                    s = s + 1
                End If
            Next
        Next
        
    End If

Else
    
    '常规法设置对照
    '确定单排ck数量
    If (row_num - 1) Mod (var_num + 1) Then
        ck_num = 1 + Int((row_num - 1) / (var_num + 1)) + 1
    Else
        ck_num = 1 + Int((row_num - 1) / (var_num + 1))
    End If
    '确定总排数和含对照的总品种数量
    c_num = Int((lastRow - 1) / (row_num - ck_num))
    If (lastRow - 1) Mod (row_num - ck_num) Then
        c_num = c_num + 1
        t_num = (lastRow - 1) + (c_num - 1) * ck_num
        If (lastRow - 1 - (c_num - 1) * (row_num - ck_num)) Mod var_num Then
            t_num = t_num + 1 + Int((lastRow - 1 - (c_num - 1) * (row_num - ck_num)) / var_num) + 1
        Else
            t_num = t_num + 1 + Int((lastRow - 1 - (c_num - 1) * (row_num - ck_num)) / var_num)
        End If
    Else
        c_num = c_num
        t_num = (lastRow - 1) + c_num * ck_num
    End If
        
    '设置排区号的数组
    ReDim arr2(1 To t_num, 1 To 4) As Variant
    
    '确定排数,并将含有对照的品种名称列入新的数组中
    If t_num Mod row_num Then
        c_num = Int(t_num / row_num) + 1
        '将含有对照的品种信息列入新数组中
        r = 1
        s = 1
        For i = 1 To c_num - 1
            For j = 1 To row_num
                arr2(r, 1) = i
                arr2(r, 2) = j
                arr2(r, 3) = r
                If j Mod (var_num + 1) = 1 Then
                    arr2(r, 4) = ck
                    r = r + 1
                ElseIf j = row_num Then
                    arr2(r, 4) = ck
                    r = r + 1
                Else
                    arr2(r, 4) = arr(s, 1)
                    r = r + 1
                    s = s + 1
                End If
            Next
        Next
        
        For j = 1 To (t_num Mod row_num)
                arr2(r, 1) = c_num
                arr2(r, 2) = j
                arr2(r, 3) = r
                If j Mod (var_num + 1) = 1 Then
                    arr2(r, 4) = ck
                    r = r + 1
                ElseIf j = (t_num Mod row_num) Then
                    arr2(r, 4) = ck
                    r = r + 1
                Else
                    arr2(r, 4) = arr(s, 1)
                    r = r + 1
                    s = s + 1
                End If
        Next
        
    Else
        c_num = Int(t_num / row_num)
        '将含有对照的品种信息列入新数组中
        r = 1
        s = 1
        For i = 1 To c_num
            For j = 1 To row_num
                arr2(r, 1) = i
                arr2(r, 2) = j
                arr2(r, 3) = r
                If j Mod (var_num + 1) = 1 Then
                    arr2(r, 4) = ck
                    r = r + 1
                ElseIf j = row_num Then
                    arr2(r, 4) = ck
                    r = r + 1
                Else
                    arr2(r, 4) = arr(s, 1)
                    r = r + 1
                    s = s + 1
                End If
            Next
        Next
        
    End If
    
    
End If

'对数组进行之字排列
If pl2 = "之字" Then
    arr2 = zhizi(arr2, t_num, row_num, c_num)
End If

' 新建一个工作表,用于生成带有排区号的整列数据
Set ws = ThisWorkbook.Sheets.Add
If sn <> "" Then
    ws.Name = sn      ' 将新工作表的名称设置为"新工作表"
End If

'工作表内数据录入
ws.Cells(1, 1).Value = "排号"
ws.Cells(1, 2).Value = "行号"
ws.Cells(1, 3).Value = "序号"
ws.Cells(1, 4).Value = "品种名称"

For i = 2 To t_num + 1
    For j = 1 To 4
        ws.Cells(i, j).Value = arr2(i - 1, j)
    Next
Next

'设置格式
Set rng2 = Range(ws.Cells(1, 1), ws.Cells(i - 1, j - 1))
'对单元格进行居中设置,添加边框
Call biankuang(ws, rng2)


Set rng = ws.Range("A1").CurrentRegion
col_max = WorksheetFunction.Max(ws.Range("A2:A" & (rng.Rows.Count)))
col_min = WorksheetFunction.Min(ws.Range("A2:A" & (rng.Rows.Count)))
row_max = WorksheetFunction.Max(ws.Range("B2:B" & (rng.Rows.Count)))
row_min = WorksheetFunction.Min(ws.Range("B2:B" & (rng.Rows.Count)))


'将行排号和品种名称放入数组,用于xlookup查询
ReDim arr5(1 To rng.Rows.Count - 1)
ReDim arr6(1 To rng.Rows.Count - 1)
For i = 2 To rng.Rows.Count
    arr5(i - 1) = CStr(rng(i, 1)) & " " & CStr(rng(i, 2))
    arr6(i - 1) = rng(i, 4)
Next

If pl = "纵向" Then
    '输入列号
    j = 1
    For i = col_min To col_max
        ws.Cells(1, j + 7).Value = i
        j = j + 1
    Next
    '输入行号
    j = 1
    For i = row_min To row_max
        ws.Cells(j + 1, 7).Value = i
        j = j + 1
    Next
                
    '将品种名称放入对应行排号的单元格中
    For i = 8 To col_max - col_min + 8
        For j = 2 To row_max - row_min + 2
            ws.Cells(j, i).Value = WorksheetFunction.XLookup(CStr(ws.Cells(1, i)) & " " & CStr(ws.Cells(j, 7)), arr5, arr6, "空", 0, 1)
        Next
    Next

Else
    '输入行号
    j = 1
    For i = row_min To row_max
        ws.Cells(1, j + 7).Value = i
        j = j + 1
    Next
    '输入列号
    j = 1
    For i = col_min To col_max
        ws.Cells(j + 1, 7).Value = i
        j = j + 1
    Next
                
    '将品种名称放入对应行排号的单元格中
    For i = 8 To row_max - row_min + 8
        For j = 2 To col_max - col_min + 2
            ws.Cells(j, i).Value = WorksheetFunction.XLookup(CStr(ws.Cells(j, 7)) & " " & CStr(ws.Cells(1, i)), arr5, arr6, "空", 0, 1)
        Next
    Next
    
End If





Application.ScreenUpdating = True       '刷新屏幕开启
Application.DisplayAlerts = True        '警告提示框开启

End Sub


Sub biankuang(ws As Worksheet, rng As Range)
    '边框和居中设置子程序
    '对单元格进行居中设置
    ws.Cells(1, 1).CurrentRegion().HorizontalAlignment = xlCenter
    ws.Cells(1, 1).VerticalAlignment = xlCenter
    '对田间种植区域添加边框
    With rng.Borders
        .LineStyle = xlContinuous
        .Weight = xlThin
        .Color = RGB(0, 0, 0) ' 黑色
    End With
End Sub

Function zhizi(arr As Variant, t_num As Integer, row_num As Integer, c_num As Integer)
    'zhizi即"之字",之字排列函数
    Dim arr3 As Variant
    Dim i_z As Integer, j_z As Integer
    
    ReDim arr3(1 To t_num, 1 To 4) As Variant
    For i_z = 1 To t_num
        If arr(i_z, 1) Mod 2 Then
            arr3(i_z, 1) = arr(i_z, 1)
            arr3(i_z, 2) = arr(i_z, 2)
            arr3(i_z, 3) = arr(i_z, 3)
            arr3(i_z, 4) = arr(i_z, 4)
        Else
            arr3(i_z, 1) = arr(i_z, 1)
            arr3(i_z, 2) = arr(row_num - arr(i_z, 2) + 1, 2)
            arr3(i_z, 3) = arr(i_z, 3)
            arr3(i_z, 4) = arr(i_z, 4)
        End If
    Next
    zhizi = arr3
End Function

设置界面如下:

参数说明:

1、是否随机排列:是对上图右侧品种顺序是否进行随机排列,如果选择将将随机排列,如果选择否,将按照给定的顺序排列

2、表格中的排列方向:若选择横向,则以行为排;若选择纵向,则以列为排

3、每排的行数:这里的行数是指田间的小区数。

4、排列方式:分为顺序排列和"之字"型配列。

5、对照设置:逢X法,即在1的位置放置对照,后面每间隔固定长度设置一个对照;常规法,即在一排的首尾设置对照,并且在一排内间隔固定长度设置一个对照

6、对照间隔数:即两个对照品种之间间隔的小区数量。

7、对照名称:默认为CK,也可以设置为具体的名称。

图1:不随机排列,排列方向横向,每排11行,之字排列,常规法设置对照

图2:不随机排列,排列方向横向,每排10行,之字排列,逢X法设置对照

图3:不随机排列,纵向,每排15行,之字排列,逢X法

图4:随机,纵向,顺序排列,每排11行,常规法设置对照,对照间隔为4行

相关推荐
不吃鱼的羊13 小时前
Excel生成DBC脚本源文件
服务器·网络·excel
chenchihwen14 小时前
数据分析时的json to excel 转换的好用小工具
数据分析·json·excel
lxxxxl16 小时前
C#调用OpenXml,读取excel行数据,遇到空单元跳过现象处理
excel
m0_7482463516 小时前
前端通过new Blob下载文档流(下载zip或excel)
前端·excel
不吃鱼不吃鱼1 天前
Excel加载项入门:原理、安装卸载流程与常见问题
excel·wps
深耕AI1 天前
在Excel中绘制ActiveX控件:解决文本编辑框定位问题
java·前端·excel
五VV1 天前
Note2024122001_Excel按成绩排名
excel
Eiceblue1 天前
Python拆分Excel - 将工作簿或工作表拆分为多个文件
开发语言·python·excel
Excel_easy1 天前
批量生成二维码,助力数字化管理-Excel易用宝
excel·wps