2016-02-19 18 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()))