删除数组中的奇数 [英] Remove odd numbers in array
问题描述
我正试图想出另一种方法来从数组中删除所有奇数。一位朋友能够提出这个解决方案,我理解它的作用,但我没有找到另一个解决方案。您对其他解决方案有什么想法吗?
JavaScript
让myArray = [1,3,5,7,9,2,4,6,8];
let it = myArray.length;
for(let i = 0; i< it; i ++){
for(let j = 0; j< myArray.length; j ++)
if(myArray [j ]%2 === 1){
myArray.splice(j,1)
break;
}
};
console.log(myArray);
你的问题是如何消除赔率,而不是如何保持平衡 - 在这种情况下结果是一样的,但你得出答案的方式可能会有所不同。并不总是有一个完美的反向函数直接插入 Array.prototype.filter
,所以这里的所有答案都将在删除元素的上下文中,我们只能检测奇数值 - 不保持均匀的元素。我将详细介绍解决问题的各种方法,但首先让我们审核您的代码
您朋友的回答
我在你的内循环上添加了一个 console.log
,这样你就可以看到你正在检查的每个元素。很容易看出这个解决方案正在做更多的工作 - 没有必要创建超过 1 循环来迭代你的数字数组。
let myArray = [1,3,5,7,9,2,4,6,8] let it = myArray.lengthfor(let i = 0; i< it; i ++){for(let j = 0; j< myArray.length; j ++){console.log('checking:',myArray [j])if( myArray [j]%2 === 1){myArray.splice(j,1)break}}} console.log(myArray)
同样重要的是,当你通过迭代来改变数组的长度时,你需要非常谨慎。例如,如果你调用 arr.splice(i,1)
,那对你的循环有什么影响?
- i右侧的所有元素将向左移位1个地方
- 数组的长度减少1
那么你的循环应如何适应呢?
- 如果所有元素都转移了在拼接后离开,这意味着我们需要再次检查相同的
i
,因为它现在指向一个新值 - 如果长度减少1,我们需要将循环退出条件更改为更快停止1次迭代
mutRejectOdds
以下答案解决了这些问题
递归函数
高度可读且直截了当但不是堆栈安全
const isOdd = x => x& 1 === 1const removeOdds =([x,... xs])=> {if(x === undefined)return [] else if(isOdd(x))return removeOdds(xs)else return [x,... removeOdds(xs)]} let data = [1,2,3,4 ,5,6,7,8] console.log(removeOdds(data))// [2,4,6,8] console.log(data)// [1,2,3,4,5,6, 7,8]
带累加器的线性迭代
堆栈安全且非常实用
const isOdd = x => x& 1 === 1const removeOdds = xs => {let acc = [] for(let x of xs)if(!isOdd(x))acc.push(x)return acc} let data = [1,2,3,4,5,6,7,8] console.log(removeOdds(data))// [2,4,6,8] console.log(data)// [1,2,3,4,5,6,7,8]
继续传递风格
大脑扭曲,但超级有趣的递归解决方案,可放在蹦床上,使堆栈安全
const isOdd = x => x& 1 === 1const identity = x => xconst removeOdds = xs => {const aux =([x,... xs],k)=> {if(x === undefined)返回k([])否则if(isOdd(x))返回aux(xs,k)否则返回aux(xs,acc => k([x,... acc] ))}返回aux(xs,identity)} let data = [1,2,3,4,5,6,7,8] console.log(removeOdds(data))// [2,4,6,8 ] console.log(数据)// [1,2,3,4,5,6,7,8]
高阶函数
类似于递归函数,但是接受另一个参数,它是要跳过的元素的函数 - 可以用线性迭代样式或连续传递样式来编写
const isOdd = x => x& 1 === 1const reject =(f,[x,... xs])=> {if(x === undefined)return [] else if(f(x))return reject(f,xs)else return [x,... reject(f,xs)]} let data = [1,2 ,3,4,5,6,7,8] console.log(reject(isOdd,data))// [2,4,6,8] console.log(data)// [1,2,3, 4,5,6,7,8]
函数组合与Array.prototype.filter
使用非常实用的内置 Array.prototype.filter
但使用函数组合返回相反的结果不
const isOdd = x => x& 1 === 1const comp = f => g => x => f(g(x))const not = x => !xconst reject =(f,xs)=> xs.filter(comp(not)(f))let data = [1,2,3,4,5,6,7,8] console.log(reject(isOdd,data))// [2,4, 6,8] console.log(数据)// [1,2,3,4,5,6,7,8]
线性迭代与原位突变
我上面实现的所有方法都不改变了原来的数据
- 在某些情况下,如果你有一个特别大的数组,您不想创建删除了奇数值的副本,您可能希望执行数据的就地修改
此答案解决原始代码中的问题
const isOdd = x => x& 1 === 1const mutRejectOdds = xs => {for(let i = 0,len = xs.length; i< len; i ++)if(isOdd(xs [i]))(xs.splice(i,1),i--,len--)} let data = [1,2,3,4,5,6,7,8] console.log(mutRejectOdds(data))// undefinedconsole.log(data)// [2,4,6,8]
I am trying to come up with another way to remove all of the odd numbers from an array. A friend was able to come up with this solution and I understand what it does, but I am failing to find another solution to it. Do you have any ideas for another solution to do this?
JavaScript
let myArray = [1,3,5,7,9,2,4,6,8];
let it = myArray.length;
for(let i=0; i<it; i++) {
for(let j=0; j<myArray.length; j++ )
if(myArray[j]%2 === 1){
myArray.splice(j,1)
break;
}
};
console.log(myArray);
Your question asks how to "remove odds", not how to "keep evens" – the result is the same in this case, but the way you derive the answer could vary. There's not always a perfect opposite function that plugs directly into Array.prototype.filter
, so all answers here will be in the context of removing elements where we only a way to detect odd values – not keeping elements that are even. I'll detail a wide variety of ways to solve your problem, but first let's review your code
your friend's answer
I added a console.log
on your inner loop so you can see each element you're checking. It's easy to see that this solution is doing more work than it has to - there's no need to create more than 1 loop to iterate thru your array of numbers.
let myArray = [1,3,5,7,9,2,4,6,8]
let it = myArray.length
for(let i = 0; i < it; i++) {
for(let j = 0; j < myArray.length; j++ ) {
console.log('checking:', myArray[j])
if(myArray[j] % 2 === 1) {
myArray.splice(j,1)
break
}
}
}
console.log(myArray)
Also important, you need to be very mindful when changing the length of an array as you're iterating thru it. For example, if you call arr.splice(i,1)
, what effect does that have on your loop?
- all elements to the right of "i" will shift left 1 place
- the length of the array decreases by 1
So how should your loop accommodate for that?
- if all elements shift left after a splice, that means we need to re-check the same
i
once more because it now points to a new value - if the length decreases by 1, we need to change the loop exit condition to stop 1 iteration sooner
The mutRejectOdds
answer below addresses these issues
recursive function
highly readable and straightforward but not stack-safe
const isOdd = x => x & 1 === 1
const removeOdds = ([x,...xs]) => {
if (x === undefined)
return []
else if (isOdd(x))
return removeOdds(xs)
else
return [x, ...removeOdds(xs)]
}
let data = [1,2,3,4,5,6,7,8]
console.log(removeOdds(data)) // [2,4,6,8]
console.log(data) // [1,2,3,4,5,6,7,8]
linear iterative with accumulator
stack-safe and highly practical
const isOdd = x => x & 1 === 1
const removeOdds = xs => {
let acc = []
for (let x of xs)
if (!isOdd(x))
acc.push(x)
return acc
}
let data = [1,2,3,4,5,6,7,8]
console.log(removeOdds(data)) // [2,4,6,8]
console.log(data) // [1,2,3,4,5,6,7,8]
continuation passing style
brain-twisting but super fun recursive solution that could be put on a trampoline to make stack-safe
const isOdd = x => x & 1 === 1
const identity = x => x
const removeOdds = xs => {
const aux = ([x,...xs], k) => {
if (x === undefined)
return k([])
else if (isOdd(x))
return aux(xs, k)
else
return aux(xs, acc => k([x, ...acc]))
}
return aux(xs, identity)
}
let data = [1,2,3,4,5,6,7,8]
console.log(removeOdds(data)) // [2,4,6,8]
console.log(data) // [1,2,3,4,5,6,7,8]
higher-order function
similar to the recursive function, but instead accepts another argument which is a function of elements to skip - could be written in linear iterative style or continuation passing style too
const isOdd = x => x & 1 === 1
const reject = (f, [x,...xs]) => {
if (x === undefined)
return []
else if (f(x))
return reject(f, xs)
else
return [x, ...reject(f, xs)]
}
let data = [1,2,3,4,5,6,7,8]
console.log(reject(isOdd, data)) // [2,4,6,8]
console.log(data) // [1,2,3,4,5,6,7,8]
function composition with Array.prototype.filter
uses the highly practical built-in Array.prototype.filter
but returns the opposite result using function composition with not
const isOdd = x => x & 1 === 1
const comp = f => g => x => f(g(x))
const not = x => !x
const reject = (f, xs) =>
xs.filter(comp(not)(f))
let data = [1,2,3,4,5,6,7,8]
console.log(reject(isOdd, data)) // [2,4,6,8]
console.log(data) // [1,2,3,4,5,6,7,8]
linear iterative with in-place mutation
all methods I implemented above do not mutate the original data
- in some cases, if you had a particularly large array and you did not want to create a copy with odd values removed, you might wish to perform an in-place modification of data
this answer addresses the issues in your original code
const isOdd = x => x & 1 === 1
const mutRejectOdds = xs => {
for (let i = 0, len = xs.length; i < len; i++)
if (isOdd(xs[i]))
(xs.splice(i,1), i--, len--)
}
let data = [1,2,3,4,5,6,7,8]
console.log(mutRejectOdds(data)) // undefined
console.log(data) // [2,4,6,8]
这篇关于删除数组中的奇数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!