![](/img/trans.png)
[英]How do I remove certain elements matching criteria from an array in javascript?
[英]Filter out / remove elements matching criteria from the end of array
我有一个字符串数组。 一些元素是空的,即''
(没有null
, undefined
或只包含空格字符的字符串)。 我需要删除这些空元素,但只能从数组的(右)端删除。 应保留非空元素之前的空元素。 如果数组中只有空字符串,则应返回空数组。
下面是我到目前为止的代码。 它有效,但我想知道 - 有没有一种方法不需要所有这些if
s? 我可以在不创建数组的内存副本的情况下完成吗?
function removeFromEnd(arr) {
t = [...arr].reverse().findIndex(e => e !== '');
if (t === 0) {
return arr;
} else if (t === -1) {
return [];
} else {
return arr.slice(0, -1 * t);
}
}
console.log(removeFromEnd(['a', 'b', '', 'c', '', '']));
console.log(removeFromEnd(['a', '', '']));
console.log(removeFromEnd(['', '', '', '', 'c']));
console.log(removeFromEnd(['', '', '', '']));
[ 'a', 'b', '', 'c' ]
[ 'a' ]
[ '', '', '', '', 'c' ]
[]
这是removeFromEnd
的尾递归实现。 我们的实施:
reverse
find
或findIndex
不必要地搜索输入 Array.prototype.reduce
或Array.prototype.reduceRight
const identity = x => x const Empty = Symbol () const removeFromEnd = ([ x = Empty, ...xs ], cont = identity) => x === Empty ? cont ([]) : removeFromEnd (xs, end => end.length === 0 && x === '' ? cont ([]) : cont ([ x, ...end ])) console.log (removeFromEnd ([ 'a', 'b', '', 'c', '', '' ])) // [ 'a', 'b', '', 'c' ] console.log (removeFromEnd ([ 'a', '', '' ])) // [ 'a' ] console.log (removeFromEnd ([ '', '', '', '', 'c' ])) // [ '', '', '', '', 'c' ] console.log (removeFromEnd ([ '', '', '', '' ])) // []
我认为removeFromEnd
可以作为高阶函数进行改进,就像Array.prototype.filter
一样
const identity = x => x const Empty = Symbol () const removeFromEnd = (f = Boolean, [ x = Empty, ...xs ], cont = identity) => x === Empty ? cont ([]) : removeFromEnd (f, xs, end => end.length === 0 && f (x) ? cont ([]) : cont ([ x, ...end ])) console.log (removeFromEnd (x => x === '', [ 'a', 'b', '', 'c', '', '', false, 0 ])) // [ 'a', 'b', '', 'c', '', '', false, 0 ] console.log (removeFromEnd (x => !x, [ 'a', 'b', '', 'c', '', '', false, 0 ])) // [ 'a', 'b', '', 'c' ]
对于初学者,这里是removeFromEnd
表达没有奇特的ES6解构语法或箭头函数
const identity = function (x) { return x } const removeFromEnd = function (f = Boolean, xs = [], i = 0, cont = identity) { if (i > xs.length) return cont ([]) else return removeFromEnd (f, xs, i + 1, function (end) { if (end.length === 0 && f (xs [i])) return cont ([]) else return cont ([ xs [i] ].concat (end)) }) } const data = [ 'a', 'b', '', 'c', '', '', false, 0 ] console.log (removeFromEnd (x => x === '', data)) // [ 'a', 'b', '', 'c', '', '', false, 0 ] console.log (removeFromEnd (x => !x, data)) // [ 'a', 'b', '', 'c' ]
上面使用的延续传递样式对您来说可能看起来很陌生,但如果您想编写removeFromEnd
则必不可少:
恢复到命令式样式,JavaScript允许我们编写没有持续复杂性的程序 - 但是,递归调用不再处于尾部位置
我分享了这个版本的程序,因为大多数对功能性思维不熟悉的人来自于编写这样的程序。 看到以不同风格表达的同一个程序,总能帮助我。 也许它可以用同样的方式帮助你^^
const removeFromEnd = function (f = Boolean, xs = [], i = 0) { if (i > xs.length) return [] const end = removeFromEnd (f, xs, i + 1) if (end.length === 0 && f (xs [i])) return [] return [ xs [i] ] .concat (end) } const data = [ 'a', 'b', '', 'c', '', '', false, 0 ] console.log (removeFromEnd (x => x === '', data)) // [ 'a', 'b', '', 'c', '', '', false, 0 ] console.log (removeFromEnd (x => !x, data)) // [ 'a', 'b', '', 'c' ]
我使用reduce并且只添加一个元素,如果它不是空字符串或者数组中已经有条目
console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', ''])); function removeFromEnd(arr) { return arr.reduceRight((a, b) => { if (b !== '' || a.length) a.push(b); return a; }, []).reverse(); }
您可以使用reduceRight
执行此操作,并在找到非空字符串的第一个元素时更改一个值。
function removeFromEnd(arr) { return arr.reduceRight((r, e) => { if (e) r.match = true; if (r.match) r.arr.unshift(e) return r; }, {arr: []}).arr } console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', '']));
另一种方法是使用函数reduceRight
和Spread syntax
。
let removeFromEnd = (arr) => arr.reduceRight((a, b) => ((b !== '' || a.length) ? [b, ...a] : a), []); console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', '']));
.as-console-wrapper { max-height: 100% !important; top: 0; }
您可以反转数组并删除元素,直到达到非空字符串。
这是一个例子:
function removeFromEnd(arr){ return arr.reverse().filter(function(v){ if(v !== ""){ this.stopRemoving = true; } return this.stopRemoving; }, {stopRemoving: false}).reverse(); } console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', '']));
这是一个使用经典循环的例子
function removeFromEnd(arr){ for(var i = arr.length - 1; i >= 0; i--){ if(arr[i] !== ""){ break; } arr.pop(); } return arr; } console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', '']));
有没有办法不需要所有这些ifs? 我可以在不创建数组的内存副本的情况下完成吗?
可能不是很实用,但是非常直接的实现:
function removeFromEnd(arr) { let i = arr.length - 1; while (arr[i] === "") i--; return arr.slice(0, i + 1); } console.log(removeFromEnd(['a', 'b', '', 'c', '', ''])); console.log(removeFromEnd(['a', '', ''])); console.log(removeFromEnd(['', '', '', '', 'c'])); console.log(removeFromEnd(['', '', '', '']));
在这里很难找到平衡...你标记了functional-programming
,@ naomik的答案向你展示了一个漂亮的功能解决方案,它与报价中的标签和关注点相匹配。
如果您只是想简化和优化,我的片段可能就够了......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.