2016-02-19 19 views
2

Node.js應用程序,編寫驗證測試。鑑於以下幾點:將用例組合使用的數組

var obj = { foo: null, bar: null, baz: null}, 
    values = [ 0, 1]; 

我需要創建ň佔每個屬性被分配可能值的每個組合的對象的數量,代表每一個可能的使用情況。因此,對於這個例子,輸出應該是對象,例如,

[ 
    { foo: 0, bar: 0, baz: 0}, 
    { foo: 0, bar: 1, baz: 0}, 
    { foo: 0, bar: 1, baz: 1}, 
    { foo: 0, bar: 0, baz: 1}, 
    { foo: 1, bar: 0, baz: 0}, 
    { foo: 1, bar: 1, baz: 0}, 
    { foo: 1, bar: 1, baz: 1}, 
    { foo: 1, bar: 0, baz: 1}, 
] 

下劃線或lodash或其他庫是可以接受的解決方案。理想情況下,我想這樣的事情:

var mapUseCases = function(current, remaining) { 
    // using Underscore, for example, pull the current case out of the 
    // possible cases, perform logic, then continue iterating through 
    // remaining cases 
    var result = current.map(function(item) { 
     // perform some kind of logic, idk 
     return magic(item); 
    }); 
    return mapUseCases(result, _.without(remaining, current)); 
} 

var myValidationHeadache = mapUseCases(currentThing, somethingElse); 

請原諒我的僞代碼,我想我打破了我的大腦。 ¯\ _(ツ)_ /¯

回答

10

任何對象長度和任何值的解決方案。

請注意,undefined值不顯示。

function buildObjects(o) { 
 
    var keys = Object.keys(o), 
 
     result = []; 
 

 
    function x(p, tupel) { 
 
     o[keys[p]].forEach(function (a) { 
 
      if (p + 1 < keys.length) { 
 
       x(p + 1, tupel.concat(a)); 
 
      } else { 
 
       result.push(tupel.concat(a).reduce(function (r, b, i) { 
 
        r[keys[i]] = b; 
 
        return r; 
 
       }, {})); 
 
      } 
 
     }); 
 
    } 
 

 
    x(0, []); 
 
    return result; 
 
} 
 

 
document.write('<pre>' + JSON.stringify(buildObjects({ 
 
    foo: [0, 1, 2], 
 
    bar: [true, false], 
 
    baz: [true, false, 0, 1, 42] 
 
}), 0, 4) + '</pre>');

+0

差不多。你擁有的是每個驗證對象的不同參數集。我試圖完成的是爲每種驗證類型設置不同的參數。因此'[foo,bar,baz]'可以使用3個不同的驗證參數,而不僅僅是一個。例如:'foo'可以使用'[0,1,2]','bar'使用'[true,false]','baz'可以使用'[true,false,0,1等...] 「我可能已經能夠更清楚地說明這一點,但在評論欄中進行格式設置。 – kmunky

+1

@kmunky,沒問題,請參閱編輯。 –

2

一種方法是從 「000」 數到 「999」 在values.length爲基礎的系統:

keys = ['foo','bar','baz'] 
 
values = ['A', 'B'] 
 

 

 
width = keys.length 
 
base = values.length 
 
out = [] 
 

 
for(var i = 0; i < Math.pow(base, width); i++) { 
 
    
 
    var d = [], j = i; 
 
    
 
    while(d.length < width) { 
 
    d.unshift(j % base) 
 
    j = Math.floor(j/base) 
 
    } 
 
    
 
    var p = {}; 
 
    
 
    for(var k = 0; k < width; k++) 
 
    p[keys[k]] = values[d[k]] 
 

 
    out.push(p) 
 
} 
 

 

 
document.write('<pre>'+JSON.stringify(out,0,3))

更新產品:

'use strict'; 
 

 
let 
 
    keys = ['foo', 'bar', 'baz'], 
 
    values = [ 
 
     ['A', 'B'], 
 
     ['a', 'b', 'c'], 
 
     [0, 1] 
 
    ]; 
 

 

 
let zip = (h, t) => 
 
    h.reduce((res, x) => 
 
     res.concat(t.map(y => [x].concat(y))) 
 
    , []); 
 

 
let product = arrays => arrays.length 
 
    ? zip(arrays[0], product(arrays.slice(1))) 
 
    : [[]]; 
 

 
let combine = (keys, values) => 
 
    keys.reduce((res, k, i) => 
 
     (res[k] = values[i], res) 
 
     , {}); 
 

 
let z = product(values).map(v => combine(keys, v)); 
 

 
z.map(x => document.write('<pre>'+JSON.stringify(x)+'</pre>'))

+0

尼斯。 +1不換。 現在,讓我把扳手放在齒輪上,如果可以的話。 (雖然,很高興將其設置爲原始問題的答案,但是,謝謝。) 這是驗證方案的一部分,因此'values'數組將在整個過程中更改。例如: var myObj = ['id','name','salary']; var idParams = [undefined,-1,0,'text']; var nameParams = [undefined,0,'text']; 所以對於'id'我想包括'idParams'的所有可能的組合,同時驗證'name'所有'nameParams'。這就是爲什麼我傾向於遞歸方法,我可以將params obj傳遞給。 – kmunky

+1

@kmunky:換句話說,你正在尋找值得的笛卡爾積。查看更新。 – georg

1

這是一個non-recursive版本的你想要什麼:

function createRange(keys, values) { 
 
    if (typeof values[0] !== typeof []) 
 
    values = keys.map(k => values); 
 
    var pointer = {}; 
 
    var repeats = 1; 
 
    keys.forEach((k, i) => { 
 
    var vLen = values[i].length; 
 
    repeats *= vLen; 
 
    pointer[k] = { 
 
     get value() { 
 
      return values[i][pointer[k].current] 
 
     }, 
 
     current: 0, 
 
     period: Math.pow(vLen, i), 
 
     inc: function() { 
 
      var ptr = pointer[k]; 
 
      ptr.current++; 
 
      if (ptr.current < vLen) return; 
 

 
      ptr.current = 0; 
 
      if (i + 1 === keys.length) return; 
 

 
      var nk = keys[i + 1]; 
 
      pointer[nk].inc() 
 
     } 
 
    }; 
 
    }); 
 
    var result = []; 
 
    for (var i = 0; i < repeats; i++) { 
 
    var o = {}; 
 
    result.push(o); 
 
    keys.forEach(k => o[k] = pointer[k].value) 
 
    pointer[keys[0]].inc(); 
 
    } 
 
    return result; 
 
} 
 

 
var objKeys = ['u', 'v', 'w', 'x', 'y', 'z']; 
 
var objValues = [ 
 
    ['1', '2', '3'], 
 
    ['a', 'b', 'c'], 
 
    ['foo', 'bar', 'baz'], 
 
    [1, 3, 2], 
 
    ['test', 'try', 'catch'], 
 
    ['Hello', 'World'], 
 
]; 
 

 
var range = createRange(objKeys, objValues); 
 
range.map(v => document.write(JSON.stringify(v).big()))