将随机配对功能从VBA转换为GAS

时间:2017-05-12 00:13:25

标签: vba excel-vba google-apps-script google-sheets excel

我一直在努力为我的低音俱乐部创建随机配对算法。我们的想法是将A列(Boaters)中的值与B列中的值(非划船者)配对。如果没有更多的非划船者,除非只有一名未配对的划船者,否则任何剩余的划船者都应配对。

我在线发现了一些VBA代码,在Excel中运行良好,但我所有的俱乐部内容都在Google表格中,我希望在GAS中具有相同的配对功能。

我已经尽力将VBA代码转换为GAS,但说实话,我对VBA有一些经验,而且我仍然是GAS的相对新手,尽管我正在学习。

我已经粘贴了下面的两个VBA功能,然后是我一直在努力的GAS转换。评论显示我遇到麻烦的地方,特别是被叫排序功能(vSortM),虽然我欢迎第二组眼睛,以确保我没有错误地编码其他东西。

任何人都可以建议我是否正确执行从VBA到GAS的转换?

我在网上找到的VBA中的配对算法:

Option Explicit 

Sub test() 
    Dim Boters(), NonBoters(), i As Long, x As Long 
    Boters = Range("a1", Range("a" & Rows.Count).End(xlUp)).Value 
    Redim Preserve Boters(1 To UBound(Boters), 1 To 2) 
    NonBoters = Range("b1", Range("b" & Rows.Count).End(xlUp)).Value 
    Redim Preserve NonBoters(1 To UBound(NonBoters), 1 To 2) 
    Randomize 
    For i = 1 To UBound(Boters) 
        Boters(i, 2) = Rnd 
    Next 
    For i = 1 To UBound(NonBoters) 
        NonBoters(i, 2) = Rnd 
    Next 
    VSortM Boters, 1, UBound(Boters), 2 
    VSortM NonBoters, 1, UBound(NonBoters), 2 
    x = Application.Min(UBound(Boters), UBound(NonBoters)) 
    With Cells(1, 4).Resize(x, 2) 
        .CurrentRegion.ClearContents 
        .Columns(1).Value = Boters 
        .Columns(2).Value = NonBoters 
    End With 
    If x < UBound(Boters) Then 
        For i = x + 1 To UBound(Boters) Step 2 
            If i + 1 > UBound(Boters) Then Exit For 
            Cells(i, 4).Value = Boters(i, 1) 
            Cells(i, 5).Value = Boters(i + 1, 1) 
        Next 
    End If 

End Sub 


Private Sub VSortM(ary, LB, UB, ref) 
    Dim M As Variant, i As Long, ii As Long, iii As Long, temp 
    i = UB: ii = LB 
    M = ary(Int((LB + UB) / 2), ref) 
    Do While ii <= i 
        Do While ary(ii, ref) < M 
            ii = ii + 1 
        Loop 
        Do While ary(i, ref) > M 
            i = i - 1 
        Loop 
        If ii <= i Then 
            For iii = LBound(ary, 2) To UBound(ary, 2) 
                temp = ary(ii, iii) 
                ary(ii, iii) = ary(i, iii): ary(i, iii) = temp 
            Next 
            ii = ii + 1: i = i - 1 
        End If 
    Loop 
    If LB < i Then VSortM ary, LB, i, ref 
    If ii < UB Then VSortM ary, ii, UB, ref 
End Sub

我尝试在GAS中转换配对算法

    function test() {
  //Get values for Column A and Column B starting at Row 5
    var ssMatch = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pairings');
    var bRange = ssMatch.getRange("A5:A").getValues();
    var nBRange = ssMatch.getRange("B5:B").getValues();
  //Determine length with data to exclude blansk
    var bLast = bRange.filter(String).length;
    var nBLast = nBRange.filter(String).length;
  //Get values for boaters & nBoaters without blanks
    var boaters = ssMatch.getRange(5,1,bLast).getValues();
    var nBoaters = ssMatch.getRange(5,2,nBLast).getValues();
//  Populate boaters & nBoaters arrays using random numbers
    for (var i = 0; i < bLast; i++) { 
        boaters[i][1] = Math.random();
      Logger.log(boaters);
        }
        for (var j = 0; j<nBLast; j++) {
        nBoaters[j][1] = Math.random();
          Logger.log(nBoaters);
        }
    vSortM (boaters, 1, bLast, 1);
    vSortM (nBoaters, 1, nBLast, 1);
  //Determine whether there are more boaters or non-boaters
    var x = Min(bLast, nBLast);
  //Write boater & nBoater values in Columns 
  //NEED SOME HELP HERE:  Certain this isn't correct for GAS
    Cells(1,4).Resize(x, 2);
        Cells.CurrentRegion.ClearContents;
        Cells.Columns(1).setValues(boaters);
        Cells.Columns(2).setValues(nBoaters);
  //If no more nBoaters, pair remaining unpaired boaters
  if (x < bLast) {
      for (var i = x + 1; i<bLast; i = i + 2) {
        if (i + 1 > bLast) { break;}
        else {
          //THINK I DID THIS RIGHT, BUT NOT SURE
            ssMatch.getRange(i,4).setValue(boaters[i][0]);
            ssMatch.getRange(i,5).setValue(boaters[i+1][0]); 
        }  
      }
    }
  }

//Having some trouble converting this from VBA to GAS
// not sure how to deal with the ary parameter and m statement
 function vSortM(ary, lB, uB, ref) {
    var temp = 0;
    var i = uB;
    var ii = lB; 
    var m = [parseInt((lB + uB) / 2), ref];
    while (ii <= i);{ 
    while ([ii, ref] < m); { 
            ii++; 
            while ([i, ref] > m); {
            i--; 
            }
            if (ii <= i); { 
            for (var iii = 0; i<=(ary, 2);) {
                temp = [ii, iii];
                [ii, iii] = [i, iii];
                [i, iii] = temp;
                }
            ii++;
            i--;
            }
        }
        if (lB < i) {
        vSortM(ary, lB, i, ref);
        }
        if (ii < uB) {
        vSortM(ary, ii, uB, ref);
        }
        }
        }

1 个答案:

答案 0 :(得分:2)

首先,我必须同意评论中的其他人。问题太宽泛了。在https://stackoverflow.com/help/dont-ask中,它表示问题应该是合理的范围。

从我在您的代码中看到的,您寻求帮助。

 //NEED SOME HELP HERE:  Certain this isn't correct for GAS
   Cells(1,4).Resize(x, 2);
     Cells.CurrentRegion.ClearContents;
     Cells.Columns(1).setValues(boaters);
     Cells.Columns(2).setValues(nBoaters);

通过使用GAS编写得非常好的文档很容易弄清楚(在去其他地方之前总是先参考它)。在GAS中,您实际上是在使用类(或者对象,如果您愿意)。在这里,您需要sheet class调整行和列的大小(2个单独的函数),然后调整range class(从工作表类中检索)以清除和设置值。

 //THINK I DID THIS RIGHT, BUT NOT SURE
   ssMatch.getRange(i,4).setValue(boaters[i][0]);
   ssMatch.getRange(i,5).setValue(boaters[i+1][0]); 

取决于您想要完成的任务。这里的语法是正确的,您为单个单元格设置了一个值。请注意,在Google工作表中,最好尝试批量调用此类调用。因此,不是逐个单元地设置值,而是获得从A1到B20的范围,并使用2D数组一次设置所有值。

最后,您需要澄清第二个功能必须做什么以及它做什么不正确。也许共享一个最小的示例表(阅读here关于Minimal,Complete和Verifiable示例)?