探索大量正确/错误属性的优雅解决方案

时间:2018-07-09 21:41:07

标签: javascript lodash

这是一个普遍存在的问题,但是我的特定用例是基于包含真/假设置的对象构建一个“友好的”过滤器名称。

以下是这些设置对象之一的示例

var settings = {
    includeMen: true,
    includeWomen: false,
    includeDependents: true,
}

业余解决方案将是一大堆if语句,例如

if(settings.includeMen && settings.includeWomen && settings.includeDependents){
    return "All People"
}

if(settings.includeMen && !settings.includeWomen && settings.includeDependents){
    return "Men and Children"
}

if(settings.includeMen && settings.includeWomen && !settings.includeDependents){
    return "Men and Women"
}
...

还有没有那么业余的想法吗? (如果有帮助,项目将使用Lodash)

4 个答案:

答案 0 :(得分:4)

 const {includeMen, includeWomen, includeDependents} = settings;

 const result = [];
 if(includeMen) result.push("Men");
 if(includeWomen) result.push("Women");
 if(includeDependents) result.push("Children");

 if(result.length === 3)
   return "All people";
 if(!result.length)
   return "No one";

 return result.join(" and ");

如果您想为每种情况提供自定义输出,则可以进行一些有趣的位移:

const {includeMen, includeWomen, includeDependents} = settings;

return [
 "No one",
 "Children",
 "Women",
 "Children and Women",
 "Men",
 "Men and Children",
 "Men and Women",
"All people"
][+includeDependents + (includeWomen << 1) + (includeMen << 2)];

(免责声明:如果您这样做,您的队友会恨您:))

答案 1 :(得分:1)

您可以通过多种方式来执行此操作, 可能我会在运行时转换对象键,然后生成字符串:

var settings = {
    includeMen: true,
    includeWomen: false,
    includeDependents: true,
}

var trueFields = Object.entries(settings).reduce((ac, [k, v]) => 
  v ? 
  [...ac, k.replace(/^include/,'')] :
  ac
,[])

var str = !trueFields.length ?
  'nobody ...' :
  trueFields.join(' and ')


console.log(str)

答案 2 :(得分:0)

我在注释中提到的一个很好的例子,它涉及使用Mozilla docs的按位运算符将多个booleans与二进制进行往返

  

自动创建蒙版

     

您可以从一组遮罩中创建多个遮罩   布尔值,如下所示:

function createMask() {
  var nMask = 0,
    nFlag = 0,
    nLen = arguments.length > 32 ? 32 : arguments.length;
  for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++);
  return nMask;
}
var mask1 = createMask(true, true, false, true); // 11, i.e.: 1011
var mask2 = createMask(false, false, true); // 4, i.e.: 0100
var mask3 = createMask(true); // 1, i.e.: 0001
// etc.

alert(mask1); // prints 11, i.e.: 1011

  

反向算法:掩码中的布尔数组

     

如果您想通过遮罩创建Array中的Booleans,则可以使用以下代码:

function arrayFromMask(nMask) {
  // nMask must be between -2147483648 and 2147483647
  if (nMask > 0x7fffffff || nMask < -0x80000000) { 
    throw new TypeError('arrayFromMask - out of range'); 
  }
  for (var nShifted = nMask, aFromMask = []; nShifted; 
       aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1);
  return aFromMask;
}

var array1 = arrayFromMask(11);
var array2 = arrayFromMask(4);
var array3 = arrayFromMask(1);

alert('[' + array1.join(', ') + ']');
// prints "[true, true, false, true]", i.e.: 11, i.e.: 1011

答案 3 :(得分:0)

您得到的各种各样的答案表明,没有一种事实上的正确方法可以实现这一目标。我的方法是创建一个易于阅读和编辑的过滤器名称定义数组,并且可以在其中搜索匹配的名称。

我喜欢这种方法的原因是,当使用新名称添加新的过滤器时,无需编辑执行搜索的逻辑。只需在过滤器名称列表中添加一个新定义即可。

这1)减少了引入错误的机会,2)将复杂性封装在易于测试且很少更改的功能内,并且3)对团队成员而言很明显。

const SETTING_PREFIX = "include";

const removeInclude = k => k.substr(SETTING_PREFIX.length, k.length);

const isTrue = x => !!x;
const isFalse = x => !x;

const getFilteredProps = (filter, predicate) => {
  return Object.keys(filter).filter(k =>
    predicate(filter[k])
  )
}

const getFilterName = filter => {
  const trueFilterProps = getFilteredProps(filter, isTrue).map(removeInclude);
  const falseFilterProps = getFilteredProps(filter, isFalse).map(removeInclude);;
  
  const filterNameDefinition = filterNames.find(definition => 
    trueFilterProps.every(key =>
        definition[0].includes(key)
    ) &&
    falseFilterProps.every(key =>
        !definition[0].includes(key)
    )
  );
  
  if (!filterNameDefinition) {
    return "Unnamed filter";
  }
  
  return filterNameDefinition[0].join(" and ");
}

const settings = {
  includeMen: false,
  includeWomen: true,
  includeDependents: true
};

const filterNames = [
  [["Men", "Women", "Dependents"], "All People"],
  [["Men", "Dependents"], "Men and Children"]
];

console.log(getFilterName(settings))