gpt4 book ai didi

javascript - 使用 reduce() 同时读入两个变量

转载 作者:搜寻专家 更新时间:2023-10-30 21:46:41 25 4
gpt4 key购买 nike

我想用 reduce() 降低以下函数的复杂性,因为这两个变量的功能几乎相似,selectedEnrolledselectedNotEnrolled

我尝试使用 map(),但在这里我没有返回任何东西,所以最终会产生副作用,我意识到这是一种糟糕的编码习惯。

countSelectNotEnrolled(selected: any) {
this.selectedNotEnrolled = selected.reduce((count, id) => {
return this.hasSteps(id)
? count + (this.userShelf.courseIds.indexOf(id) === -1 ? 1 : 0)
: count;
}, 0);
this.selectedEnrolled = selected.reduce((count, id) => {
return this.hasSteps(id)
? count + (this.userShelf.courseIds.indexOf(id) === -1 ? 0 : 1)
: count;
}, 0);
}

感谢您的帮助。

最佳答案

唯一的区别似乎是您作为增量返回的内容,这取决于当前 ID 是否是 this.userShelf.courseIds 数组的一部分。

countSelectNotEnrolled(selected: any) {
this.selectedNotEnrolled = selected.reduce((count, id) => {
return this.hasSteps(id)
? count + (this.userShelf.courseIds.indexOf(id) === -1 ? 1 : 0)
// ^^^^^
: count;
}, 0);
this.selectedEnrolled = selected.reduce((count, id) => {
return this.hasSteps(id)
? count + (this.userShelf.courseIds.indexOf(id) === -1 ? 0 : 1)
// ^^^^^
: count;
}, 0);
}

一种更普遍适用于重构模式的方法是在创建函数时将差异提取为动态部分。

您可以创建一个返回另一个函数并接受此增量值作为参数的函数。然后您可以使用该函数创建两个函数,一个对 selectedNotEnrolled 的计数求和,另一个对 selectedEnrolled 的计数求和。

注意:使用 Array.prototype.includesArray.prototype.indexOf干净一点在检查数组中是否存在时。

function createEnrolmentSum( // the wrapper function accepts the dynamic setup logic
incrementIfSelected,
incrementIfUnselected = incrementIfSelected === 1 ? 0 : 1
) {
return function (selected) { // <--- return a function that does the common logic
return selected.reduce((count, id) => {
return this.hasSteps(id)
? count +
(this.userShelf.courseIds.includes(id) // <-- using includes is a bit cleaner
? incrementIfSelected
: incrementIfUnselected)
: count;
}, 0);
};
}

// ...

// create instance methods so we maintain proper `this` behavior
getEnrolledSum = createEnrolmentSum(1);
getNotEnrolledSum = createEnrolmentSum(0);

countSelectNotEnrolled(selected: any) {
this.selectedNotEnrolled = this.getNotEnrolledSum();
this.selectedEnrolled = this.getEnrolledSum();
}

以上只是对如何重构任何类似代码的一般演示。可以说,这个特定的 api 不是很可读:

// this api isn't very readable because it's not clear
// what `1` or `0` mean as arguments
getEnrolledSum = createEnrolmentSum(1);
getNotEnrolledSum = createEnrolmentSum(0);

您可以使用配置对象提高这种可读性:

getEnrolledSum = createEnrolmentSum({
incrementIfSelected: 1,
incrementIfUnselected: 0
});
getNotEnrolledSum = createEnrolmentSum({
incrementIfSelected: 0,
incrementIfUnselected: 1
});

但这并没有改善很多事情,因为代码,尽管 DRY , 绝对是复杂的。

我建议,对于您的特定情况,明显的起始解决方案是在一个循环中计算两个总和。这不需要太多的复杂性,而且会更快,因为您将只遍历 selected 数组一次而不是两次。

countSelectNotEnrolled(selected) {
let selectedNotEnrolled = 0,
selectedEnrolled = 0;

for (const id of selected) {
if (this.hasSteps(id)) {
if (this.userShelf.courseIds.includes(id)) {
selectedEnrolled += 1;
} else {
selectedNotEnrolled += 1;
}
}
}

this.selectedNotEnrolled = selectedNotEnrolled;
this.selectedEnrolled = selectedEnrolled;
}

如果你确实想使用数组缩减,你可以使用一个对象来携带两个变量通过迭代循环:

countSelectNotEnrolled(selected) {
const { selectedNotEnrolled, selectedEnrolled } = selected.reduce(
(result, id) => {
if (this.hasSteps(id)) {
if (this.userShelf.courseIds.includes(id)) {
result.selectedEnrolled += 1;
} else {
result.selectedNotEnrolled += 1;
}
}
return result;
},
{ selectedNotEnrolled: 0, selectedEnrolled: 0 } // <-- reduction result contains both variables
);

this.selectedNotEnrolled = selectedNotEnrolled;
this.selectedEnrolled = selectedEnrolled;
}

要去除一些嵌套,我们可以先过滤掉所有没有steps的id:

countSelectNotEnrolled(selected) {
const { selectedNotEnrolled, selectedEnrolled } = selected
.filter(this.hasSteps) // <-- apply the filter first
.reduce(
(result, id) => {
if (this.userShelf.courseIds.includes(id)) {
result.selectedEnrolled += 1;
} else {
result.selectedNotEnrolled += 1;
}
return result;
},
{ selectedNotEnrolled: 0, selectedEnrolled: 0 }
);

this.selectedNotEnrolled = selectedNotEnrolled;
this.selectedEnrolled = selectedEnrolled;
}

如果您已经在您的实例上初始化了必要的变量并且更新实例数据没有重大的性能损失,您也可以直接为其赋值:

countSelectNotEnrolled(selected) {
// setup
this.selectedEnrolled = 0;
this.selectedNotEnrolled = 0;

// sum
selected
.filter(this.hasSteps)
.forEach(id => {
if (this.userShelf.courseIds.includes(id)) {
this.selectedEnrolled += 1;
} else {
this.selectedNotEnrolled += 1;
}
});
}

或者,您可以利用过滤将属于已注册和未注册的 ID 拆分,然后只提取长度:

countSelectNotEnrolled(selected) {
const selectedWithSteps = selected.filter(this.hasSteps);

this.selectedNotEnrolled = selectedWithSteps.filter(
id => !this.userShelf.courseIds.includes(id)
).length;

this.selectedEnrolled = selectedWithSteps.filter(id =>
this.userShelf.courseIds.includes(id)
).length;
}

其实不需要二次过滤,我们可以互相表示已注册和未注册:

countSelectNotEnrolled(selected) {
const selectedWithSteps = selected.filter(this.hasSteps);

this.selectedNotEnrolled = selectedWithSteps.filter(
id => !this.userShelf.courseIds.includes(id)
).length;

this.selectedEnrolled = selectedWithSteps.length - this.selectedNotEnrolled;
}

总的来说,我给出的最佳重构建议是少担心特定模式,多担心代码可读性。我们正在用这些高级语言(如 JavaScript)编写,以便人类可以阅读它,机器不在乎,它们可以很好地阅读二进制文件。我们应该编写花费最少的人类认知努力来理解的代码 🙂

关于javascript - 使用 reduce() 同时读入两个变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53927787/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com