2015-07-11 52 views
1

下劃線mixin和下面的函數以兩種不同的方式完成相同的事情,它們獲取數組的所有對。我想知道如何創建一個函數(閉包?),使我能夠傳遞多少個「對」或我想要的數組項目,而不是每次嵌套for loopsrange-maps以編程方式生成嵌套for循環

getPairs: function(arr){ 
    return _.chain(_.range(arr.length)) 
    .map(function(setOne){ 
    return _.chain(_.range(arr.length)) 
    .map(function(setTwo){ 
     return [ 
     arr[setOne], 
     arr[setTwo], 
     ] 
    }) 
    .value() 
    }) 
    .value() 
} 

function getPairs(arr){ 
    var pairs = [] 
    for(var i = 0; i < arr.length; i++){ 
    for(var p = 0; p < arr.length; p++){ 
     var pair = [ 
     arr[i], 
     arr[p], 
     ] 
     pairs.push() 
    } 
    } 
    return pairs 
} 
+0

奇怪。我正要問一個非常相關的問題,而且這個問題已經列在了最重要的問題上,早在一分鐘之前就已經問過了。 – Alec

+0

我沒有在下劃線代碼中發現,下面的函數缺少'.push()'我想。你能添加一個你想要的輸入和輸出的例子嗎? – Sergio

+0

「多少對」是什麼意思?你的意思是限制結果數組的大小嗎? – heartyporridge

回答

0

有趣的問題。爲了得到一個簡單的解決方案,我必須考慮一下。事實上,整個事情可以通過兩個for循環和一些沉重的數學來完成。下面的代碼:

function getGroupings(arr, numPerGroup){ 
    numPerGroup > 1 || (numPerGroup = 2); 
    var groups = Math.pow(arr.length, numPerGroup); 
    var groupings = []; 
    for (var i = 0; i < numPerGroup; i++) { 
     for (var j = 0; j < groups; j++) { 
      groupings[j] || groupings.push(Array(numPerGroup)); 
      var index = Math.floor(j/Math.pow(arr.length, i)) % arr.length; 
      groupings[j][i] = arr[index]; 
      if (i === numPerGroup - 1) groupings[j] = groupings[j].reverse(); 
     } 
    } 
    return groupings; 
} 

上是如何工作的幾個注意事項:

  • 它一旦運行外`for`循環在內部陣列的每個項目,以及內`for`一次循環爲外部數組中的每個項目。倒退,你可能會說。
  • 內部`for`循環的工作方式類似於一個二進制時鐘,其中(時鐘的值)===(我們想要訪問的傳入數組的索引)。
  • Ñ =(傳入的陣列的長度)時,將每一次遞增時鐘在一個人的地方,一個(Ñ^1)個如經常在(Ñ^1) ( n^2)th經常在( n^2)的位置,等等,直到( n^num-per-group)的地方。
  • 在最後一次迭代中,它顛倒了所有內部數組以實際上最後一個位置,倒數第二位等等......不一定必要,但產生一個更多的預期產出。

例子:

假設你有一個數組,var arr = [3, 6, 9],和你想的3-- getGroupings(arr, 3);所有可能的分組。組的實際數量爲arr.length^3 = 27,因此該函數將生成一個由27個數組組成的數組。

(忽略外部for循環 - 想象它的所有迭代一次發生)二進制時鐘從0開始,所以第一個分組是arr[0], arr[0], arr[0] - [3, 3, 3]

在下一次迭代中,1的位置前進一個 - arr[0], arr[0], arr[1] - [3, 3, 6],然後[3, 3, 9]

接下來是3個地方前進的時間和地點重置 - arr[0], arr[1], arr[0],所以第4組是[3, 6, 3]。等到第27陣列,[9, 9, 9]

這是JSFiddle。試試看!

0

由於這個問題是更多的關於算法的實現我使用SWIFT實現它:

// provide 2 parameters, an array and the size of one group of elements 
// [[T]] means an array of an array of type T (placeholder for anything) 
func getPair<T>(array: [T], pairCount: Int) -> [[T]] { 
    if pairCount <= 1 { 
     // puts each element of array in a separate array: 
     // [3, 6, 7] -> [[3], [6], [7]] 
     return array.map{ [$0] } 
    } 
    // returns a flattened array of all possible element combinations 
    // flatMap: array gets mapped to all other possible combinations of one less than pairCount and gets flattened/concatenated 
    // el1: element of the array which can be used in the closure 
    return array.flatMap{ el1 in 
     // smaller pairs are mapped to bigger ones 
     // el2: element of the smaller pairs (one small pair) which can be used in the closure 
     return getPair(array, pairCount - 1).map{ el2 in 
      return [el1] + el2 
     } 
    } 
} 

正如你可以看到這個遞歸函數的代碼行方面非常有效,但在與其他C類似的版本相比,它是2-22(平均:4-6)倍,特別是對於一個大的pairCounts。

這裏是另一個版本:

// helper function which "creates" for loops and passes the indexes to a closure which takes an array of indexes 
// indexes = [2, 3, 4] ==> for 4 times { for 3 times { for 2 times {} } } 
// the corresponding passed indexes range from [0, 0, 0] to [2 - 1, 3 - 1, 4 - 1] so you can pass array.count directly 
// therefore the index of the inner for loop can be accessed with passedArray[0] and so on 
func forIndexes(indexes: [Int], closure: [Int] ->()) { 
    if indexes.count == 0 { return } 

    // array which gets passed to the closure and modified over time 
    var currentIndexes = Array(count: indexes.count, repeatedValue: 0) 

    // maximum overall count of inner for loop: [2, 4, 5] => 2*4*5 = 40 
    var count = 1 
    for var i = 0; i < indexes.count; i++ { 
     count *= indexes[i] 
    } 

    for var i = 0; i < count; i++ { 
     // call closure with currentIndexes 
     closure(currentIndexes) 

     // increment first current index and check whether the other ones have to be updated 
     if ++currentIndexes[0] == indexes[0] { 
      // condition: j < indexes.count - 1 => prevent out of bounds exception for: currentIndexes[j+1]++ 
      for var j = 0; j < indexes.count - 1; j++ { 
       if currentIndexes[j] >= indexes[j] { 
        currentIndexes[j] -= indexes[j] 
        currentIndexes[j+1]++ 
       } 
      } 
     } 
    } 
} 

func getPair2<T>(array: [T], pairCount: Int) -> [[T]] { 
    var result = [[T]]() 
    // pair count determines the depth of the nested for loops while array.count specifies the loop count 
    forIndexes(Array(count: pairCount, repeatedValue: array.count), closure: { indexes in 
     // map array elements from all possible indexes 
     result.append(indexes.map{ index in 
      return array[index] 
     }) 
    }) 
    return result 
}