2015-07-10 176 views
1

如何从数组的左侧和右侧修剪连续的虚假成员?修整数组的左侧和右侧

我想编写,做这样的事情

getLookupKey('prefix', 'prefix', 'middle', 'suffix', 'suffix'); 
// => 'prefix.prefix.middle.suffix.suffix' 

getLookupKey(null, 'prefix', 'middle', 'suffix', null); 
// => 'prefix.middle.suffix' 

getLookupKey('name'); 
// => 'name' 

getLookupKey(); 
// => '' 

getLookupKey('prefix', null, 'suffix'); 
// => throws error 

getLookupKey采用可变数量的参数,并产生一个查找键的方法。

我想这种方法忽略了阵列的左侧和右侧空,但抛出,如果有在中间的任何空值。

这里有一些行为规则:

  • 数组成员计算结果为假起点从数组的开始,直到成员计算为真应该被删除。
  • 评估为false的数组成员从数组的末尾开始,直到成员的计算结果为true应该被删除。
  • 在评估为true的成员之间评估为false的成员应导致该方法抛出错误。
+1

为什么这是downvoted这我不清楚。这个问题没有得到解决,独特和实用,我的答案是有用的,据我可以告诉...有什么我错过了? – Nate

+0

也许你的回答必须包含在你的问题中,以显示你的努力。 –

+0

我不明白为什么。这是一个解决方案,而不是试图找到解决方案。如果这是一个答案,它不应该在答案部分? – Nate

回答

1

有趣的问题,这是我采取的解决方案。我使用dropWhiledropRightWhile来完成大部分繁重工作。

dropWhile将丢弃从左侧的所有错误值,直到找到真值。 dropRightWhile将从右侧删除所有错误的值直到找到真值。 any方法用于测试成员内是否存在任何错误值。

isFalse方法只是一种检查falsey值的方法。这只是一个js技巧将任何值转换为布尔值。

function log(value) { 
 
    document.getElementById("output").innerHTML += JSON.stringify(value, null, 2) + "\n" 
 
} 
 

 
function getLookupKey() { 
 
    var keyParts = trimArrayFalsey(_.toArray(arguments)); 
 
    if (_.any(keyParts, isFalse)) { 
 
     throw new Error('Center null'); 
 
    } 
 
    return keyParts.join('.'); 
 
} 
 

 
function trimArrayFalsey(arr) { 
 
    return _.chain(arr) 
 
      .dropWhile(isFalse) 
 
      .dropRightWhile(isFalse) 
 
      .value(); 
 
} 
 
     
 
function isFalse(value) { 
 
    return !!!value; 
 
} 
 

 
log(getLookupKey('prefix', 'prefix', 'middle', 'suffix', 'suffix')); 
 
// => 'prefix.prefix.middle.suffix.suffix' 
 

 
log(getLookupKey(null, 'prefix', 'middle', 'suffix', null)); 
 
// => 'prefix.middle.suffix' 
 

 
log(getLookupKey('name')); 
 
// => 'name' 
 

 
log(getLookupKey()); 
 
// => '' 
 

 
log(getLookupKey('prefix', null, 'suffix'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script> 
 
<pre id="output"></pre>

+0

'!!! value;'better written'!value;' – Xotic750

+0

@ Xotic750我不记得我在哪里读过它,但有一些不太明显的情况,'!value'不起作用,'!!! value'会确保它能正常工作,但我不记得我在哪里阅读。无论如何,它肯定会最好使用'!value' ..它是那些隐晦的浏览器特定的错误之一.. – Pete

+0

我不知道'dropWhile'等。这是一个有趣的事情。谢谢。 – Nate

0

实现:

function getLookupKey(){ 
    var keyParts = trimArrayFalsey(_.toArray(arguments)); 
    if (! _.isArray(keyParts) || ! _.all(keyParts)) { 
    throw new Error('Center null'); 
    } 

    return keyParts.join('.'); 
} 

相关方法:

var _ = require("lodash"); 

/** 
* getArrayRightFalsyCount(array, [predicate=_.identity]) 
* Get a count of the contiguous falsey members on the right of the array. 
*/ 
function getArrayRightFalsyCount(arr, predicate){ 
    if (! _.isArray(arr)) return 0; 
    predicate = predicate || _.identity; 
    return _.reduce(arr, function(result, value, index){ 
    return predicate(value) ? 0 : result + 1; 
    }, 0); 
} 

/** 
* getArrayLeftFalsyCount(array, [predicate=_.identity]) 
* Get a count of the contiguous falsey members on the left of the array. 
*/ 
function getArrayLeftFalsyCount(arr, predicate){ 
    if (! _.isArray(arr)) return 0; 
    return _.reduceRight(arr, function(result, value, index){ 
    return value ? 0 : result + 1; 
    }, 0); 
} 

/** 
* trimArrayFalsey(array, [predicate=_.identity]) 
* Trims the contiguous falsey members from the left and 
* right edge of the array, but not from the middle. 
*/ 
function trimArrayFalsey(arr, predicate){ 
    if (! _.isArray(arr)) return null; 
    return _.slice(
    arr, 
    getArrayLeftFalsyCount(arr, predicate), 
    arr.length - getArrayRightFalsyCount(arr, predicate) 
); 
} 

测试它:

getArrayRightFalsyCount(["a", false, "b", false, null, "", 0]); 
// => 4 

getArrayLeftFalsyCount([0, "", null, false, "b", false, "a"]); 
// => 4 

trimArrayFalsey([]); 
// => [] 

trimArrayFalsey(["a", "b", "c"]); 
// => ["a", "b", "c"] 

trimArrayFalsey([null, null, false, "a", null, "b", "c", 0, ""]); 
// => ["a", null, "b", "c"] 

getLookupKey(null, null, "a", "b", "c", null, null); 
// => "a.b.c" 

getLookupKey("a", null, "b"); 
// => Uncaught Error: Center null 
+0

我的确编辑了答案,我希望能够让它更清楚,但是我已经看到很多只是代码没有探究的答案,只要解决了问题,我就不会看到有什么问题。 – Nate

+0

我个人赞成这样的帖子,因为他们通常没有帮助。我们试图成为知识库,而不是单独的复制粘贴源。 –

+0

@MartijnPieters这是我自己写的一个独特的答案。这是对问题的回答,甚至在编辑有解决答案的代码之前。我很欣赏你的意见,我只是希望我能更好地理解它。 – Nate

1

不使用任何库,只是纯粹的JavaScript,因此有更多的代码比图书馆的含糖语法要好。应该比使用多个循环有更好的性能,因为它只是一个单一的循环,对于更多的参数会更明显。

作品通过查看阵列状arguments对象的每个端部,标志着startend位置处的元素不计算false。一旦标记进一步的元素连接到result字符串。如果我们有内容,那么我们串接的startend元素(如果存在的话)给予的全部内容,最后return荷兰国际集团的result

function getLookupKey() { 
 
    var length = arguments.length, 
 
     result = '', 
 
     index, 
 
     start, 
 
     end, 
 
     stop, 
 
     value; 
 

 
    for (index = 0; index < length; index += 1) { 
 
     if (arguments[index]) { 
 
      start = index; 
 
      break; 
 
     } 
 
    } 
 

 
    for (index = length; index > start; index -= 1) { 
 
     if (arguments[index]) { 
 
      end = index; 
 
      break; 
 
     } 
 
    } 
 

 
    stop = end - 1; 
 
    for (index = start + 1; index < end; index += 1) { 
 
     value = arguments[index]; 
 
     if (!value) { 
 
      throw new SyntaxError('middle evaluates false'); 
 
     } 
 
     
 
     result += value; 
 
     if (index !== stop) { 
 
      result += '.'; 
 
     } 
 
    } 
 

 
    if (typeof start === 'number') { 
 
     if (result) { 
 
      result = '.' + result; 
 
     } 
 

 
     result = arguments[start] + result; 
 
    } 
 

 
    if (typeof end === 'number') { 
 
     result += '.' + arguments[end]; 
 
    } 
 

 
    return result; 
 
} 
 

 
function log(str) { 
 
    document.getElementById('out').textContent += str + '\n'; 
 
} 
 

 
var tests = [ 
 
    [ 
 
     [null, 'middle'], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, null, 'middle', null, null], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, 'middle', null, null, null], 'middle' 
 
    ], 
 
    [ 
 
     ['prefix1', 'prefix2', 'middle', 'suffix1', 'suffix2'], 'prefix1.prefix2.middle.suffix1.suffix2' 
 
    ], 
 
    [ 
 
     [null, 'prefix', 'middle', 'suffix', null], 'prefix.middle.suffix' 
 
    ], 
 
    [ 
 
     ['name'], 'name' 
 
    ], 
 
    [ 
 
     [null], '' 
 
    ], 
 
    [ 
 
     [null, null, null, null], '' 
 
    ], 
 
    [ 
 
     ['a', null, null, null], 'a' 
 
    ], 
 
    [ 
 
     [null, null, null, 'b'], 'b' 
 
    ], 
 
    [ 
 
     [], '' 
 
    ], 
 
    [ 
 
     ['prefix', null, 'suffix'], Error 
 
    ], 
 
    [ 
 
     [null, null, 'a', 'b', 'c', null, null], 'a.b.c' 
 
    ], 
 
    [ 
 
     ['a', null, 'b'], Error 
 
    ], 
 
    [ 
 
     [null, 'middle', null], 'middle' 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, 'middle2', 'middle3', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', 'middle2', 'middle3', null, 'middle4', 'middle5', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, null, null, null, 'middle2', null], Error 
 
    ] 
 
]; 
 

 
function test(fn) { 
 
    var length = tests.length, 
 
     index, 
 
     expected, 
 
     args, 
 
     actual; 
 

 
    for (index = 0; index < length; index += 1) { 
 
     args = tests[index][0]; 
 
     expected = tests[index][1]; 
 
     if (typeof expected === 'string') { 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else if (expected === Error) { 
 
      expected = 'middle evaluates false'; 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else { 
 
      log('Test ' + index + ': coder error'); 
 
     } 
 
    } 
 
} 
 

 
test(getLookupKey);
<pre id="out"></pre>

简单但比上述效率较低,在ES5

简单但效率较低再次

function getLookupKey() { 
 
    var arr = Array.prototype.reduce.call(arguments, function (acc, arg) { 
 
     if (arg || acc.length) { 
 
      acc.push(arg); 
 
     } 
 
     
 
     return acc; 
 
    }, []).reduceRight(function (acc, arg) { 
 
     if (arg || acc.length) { 
 
      acc.unshift(arg); 
 
     } 
 
     
 
     return acc; 
 
    }, []); 
 
    
 
    if (!arr.every(Boolean)) { 
 
     throw new SyntaxError('middle evaluates false'); 
 
    } 
 
    
 
    return arr.join('.'); 
 
} 
 

 
function log(str) { 
 
    document.getElementById('out').textContent += str + '\n'; 
 
} 
 

 
var tests = [ 
 
    [ 
 
     [null, 'middle'], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, null, 'middle', null, null], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, 'middle', null, null, null], 'middle' 
 
    ], 
 
    [ 
 
     ['prefix1', 'prefix2', 'middle', 'suffix1', 'suffix2'], 'prefix1.prefix2.middle.suffix1.suffix2' 
 
    ], 
 
    [ 
 
     [null, 'prefix', 'middle', 'suffix', null], 'prefix.middle.suffix' 
 
    ], 
 
    [ 
 
     ['name'], 'name' 
 
    ], 
 
    [ 
 
     [null], '' 
 
    ], 
 
    [ 
 
     [null, null, null, null], '' 
 
    ], 
 
    [ 
 
     ['a', null, null, null], 'a' 
 
    ], 
 
    [ 
 
     [null, null, null, 'b'], 'b' 
 
    ], 
 
    [ 
 
     [], '' 
 
    ], 
 
    [ 
 
     ['prefix', null, 'suffix'], Error 
 
    ], 
 
    [ 
 
     [null, null, 'a', 'b', 'c', null, null], 'a.b.c' 
 
    ], 
 
    [ 
 
     ['a', null, 'b'], Error 
 
    ], 
 
    [ 
 
     [null, 'middle', null], 'middle' 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, 'middle2', 'middle3', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', 'middle2', 'middle3', null, 'middle4', 'middle5', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, null, null, null, 'middle2', null], Error 
 
    ] 
 
]; 
 

 
function test(fn) { 
 
    var length = tests.length, 
 
     index, 
 
     expected, 
 
     args, 
 
     actual; 
 

 
    for (index = 0; index < length; index += 1) { 
 
     args = tests[index][0]; 
 
     expected = tests[index][1]; 
 
     if (typeof expected === 'string') { 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else if (expected === Error) { 
 
      expected = 'middle evaluates false'; 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else { 
 
      log('Test ' + index + ': coder error'); 
 
     } 
 
    } 
 
} 
 

 
test(getLookupKey);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.1.7/es5-shim.min.js"></script> 
 
<pre id="out"></pre>

,在ES6

function fVal(test, alt) { 
 
    return test !== -1 ? test : alt; 
 
} 
 

 
function getLookupKey() { 
 
    var arr = Array.prototype.slice.call(arguments), 
 
     length = arr.length, 
 
     begin = fVal(arr.findIndex(Boolean), length), 
 
     end = length - fVal(arr.slice().reverse().findIndex(Boolean), 0); 
 

 
    arr = arr.slice(begin, end); 
 
    if (!arr.every(Boolean)) { 
 
     throw new SyntaxError('middle evaluates false'); 
 
    } 
 

 
    return arr.join('.'); 
 
} 
 

 
function log(str) { 
 
    document.getElementById('out').textContent += str + '\n'; 
 
} 
 

 
var tests = [ 
 
    [ 
 
     [null, 'middle'], 'middle'], 
 
    [ 
 
     [null, null, null, 'middle', null, null], 'middle'], 
 
    [ 
 
     [null, null, 'middle', null, null, null], 'middle'], 
 
    [ 
 
     ['prefix1', 'prefix2', 'middle', 'suffix1', 'suffix2'], 'prefix1.prefix2.middle.suffix1.suffix2'], 
 
    [ 
 
     [null, 'prefix', 'middle', 'suffix', null], 'prefix.middle.suffix'], 
 
    [ 
 
     ['name'], 'name'], 
 
    [ 
 
     [null], ''], 
 
    [ 
 
     [null, null, null, null], ''], 
 
    [ 
 
     ['a', null, null, null], 'a'], 
 
    [ 
 
     [null, null, null, 'b'], 'b'], 
 
    [ 
 
     [], ''], 
 
    [ 
 
     ['prefix', null, 'suffix'], Error], 
 
    [ 
 
     [null, null, 'a', 'b', 'c', null, null], 'a.b.c'], 
 
    [ 
 
     ['a', null, 'b'], Error], 
 
    [ 
 
     [null, 'middle', null], 'middle'], 
 
    [ 
 
     [null, 'middle1', null, 'middle2', 'middle3', null], Error], 
 
    [ 
 
     [null, 'middle1', 'middle2', 'middle3', null, 'middle4', 'middle5', null], Error], 
 
    [ 
 
     [null, 'middle1', null, null, null, null, 'middle2', null], Error] 
 
]; 
 

 
function test(fn) { 
 
    var length = tests.length, 
 
     index, 
 
     expected, 
 
     args, 
 
     actual; 
 

 
    for (index = 0; index < length; index += 1) { 
 
     args = tests[index][0]; 
 
     expected = tests[index][1]; 
 
     if (typeof expected === 'string') { 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 

 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else if (expected === Error) { 
 
      expected = 'middle evaluates false'; 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 

 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else { 
 
      log('Test ' + index + ': coder error'); 
 
     } 
 
    } 
 
} 
 

 
test(getLookupKey);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.32.2/es6-shim.min.js"></script> 
 
<pre id="out"></pre>

简单,但效率较低再次,在lodash(可能比ES5更高效,最有可能比ES6,没有可用的目前测试的假设jsPerf更好)。

function getLookupKey() { 
 
    var slice =_(arguments).dropWhile(_.isEmpty).dropRightWhile(_.isEmpty); 
 
    
 
    if (!slice.all(Boolean)) { 
 
     throw new SyntaxError('middle evaluates false'); 
 
    } 
 
    
 
    return slice.join('.'); 
 
} 
 

 
function log(str) { 
 
    document.getElementById('out').textContent += str + '\n'; 
 
} 
 

 
var tests = [ 
 
    [ 
 
     [null, 'middle'], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, null, 'middle', null, null], 'middle' 
 
    ], 
 
    [ 
 
     [null, null, 'middle', null, null, null], 'middle' 
 
    ], 
 
    [ 
 
     ['prefix1', 'prefix2', 'middle', 'suffix1', 'suffix2'], 'prefix1.prefix2.middle.suffix1.suffix2' 
 
    ], 
 
    [ 
 
     [null, 'prefix', 'middle', 'suffix', null], 'prefix.middle.suffix' 
 
    ], 
 
    [ 
 
     ['name'], 'name' 
 
    ], 
 
    [ 
 
     [null], '' 
 
    ], 
 
    [ 
 
     [null, null, null, null], '' 
 
    ], 
 
    [ 
 
     ['a', null, null, null], 'a' 
 
    ], 
 
    [ 
 
     [null, null, null, 'b'], 'b' 
 
    ], 
 
    [ 
 
     [], '' 
 
    ], 
 
    [ 
 
     ['prefix', null, 'suffix'], Error 
 
    ], 
 
    [ 
 
     [null, null, 'a', 'b', 'c', null, null], 'a.b.c' 
 
    ], 
 
    [ 
 
     ['a', null, 'b'], Error 
 
    ], 
 
    [ 
 
     [null, 'middle', null], 'middle' 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, 'middle2', 'middle3', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', 'middle2', 'middle3', null, 'middle4', 'middle5', null], Error 
 
    ], 
 
    [ 
 
     [null, 'middle1', null, null, null, null, 'middle2', null], Error 
 
    ] 
 
]; 
 

 
function test(fn) { 
 
    var length = tests.length, 
 
     index, 
 
     expected, 
 
     args, 
 
     actual; 
 

 
    for (index = 0; index < length; index += 1) { 
 
     args = tests[index][0]; 
 
     expected = tests[index][1]; 
 
     if (typeof expected === 'string') { 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else if (expected === Error) { 
 
      expected = 'middle evaluates false'; 
 
      try { 
 
       actual = fn.apply(null, args); 
 
      } catch (e) { 
 
       actual = e.message; 
 
      } 
 
      
 
      log('Test ' + index + ': Expected: "' + expected + '" Actual: "' + actual + '"'); 
 
     } else { 
 
      log('Test ' + index + ': coder error'); 
 
     } 
 
    } 
 
} 
 

 
test(getLookupKey);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script> 
 
<pre id="out"></pre>

+0

没有特定的Lodash要求。既然我的问题已经解决了,那么在我给出接受的答案之前,我会等待其他人投票。 – Nate

1

dropWhile()dropRightWhile()是你的朋友:

function getLookupKey() { 
    var falsey = _.negate(_.identity); 

    var result = _(arguments) 
     .dropWhile(falsey) 
     .dropRightWhile(falsey) 
     .join('.'); 

    if (_.includes(result, '..')) { 
     throw new Error('invalid'); 
    } else if (_.isUndefined(result)) { 
     result = ''; 
    } 

    return result; 
}