测试在 Javascript 中使用 reduce() 时是否到达数组的最后一项
Testing whether you reach an array's last item when using reduce() in Javascript
我正在尝试使用 .reduce()
来实现 .join()
的等价物来回答 executeprogram.com 上的测验。我的代码通过了测试,但看起来很难看。我以丑陋的方式解决的具体问题是:构造的 join()
函数将一个数组和一个分隔符作为参数,但是在构造结果连接时,不应在数组的最后一项之后插入分隔符输出。这意味着我必须测试,当用reduce()
遍历数组时,我是否在最后一项(这样我就可以跳过使用分隔符)[哎呀:见下面的注释]。如果数组中有重复值,则使用 indexOf
或 lastIndexOf
不起作用。所以我创建了一个计数器。我不喜欢它。我很乐意提供有关如何更好地做到这一点的建议。这是代码:
function join(arr, separator) {
let counter = 0;
if (arr.length === 0) { return(''); }
else {
return (
arr.reduce((accumulator, item) =>
{
if (counter === arr.length - 1) {
return accumulator + item;
} else {
counter += 1;
return accumulator + item + separator;
}
},
'')
);
}
}
测试及其预期输出如下。同样,上面的函数通过了所有测试,但我认为必须有更好的方法。
> join(['a'], ',')
Expected: 'a'
> join(['a', 'b'], ',')
Expected: 'a,b'
> join(['a', 'b', 'c'], '')
Expected: 'abc'
> join(['a', 'b', 'c', 'd'], 'x')
Expected: 'axbxcxd'
> join(['a', 'b'], 'COMMA')
Expected: 'aCOMMAb'
> join(['', '', ''], ',')
Expected: ',,'
> join([], ',')
Expected: ''
注意:在看到所有有用的答案后,我意识到 真正的 造成这段丑陋代码的原因是我错误的假设分隔符出现在项目“之后”。实际上,分隔符出现在 between 项之间,如果将它插入 before[=33],则可以使它出现在每个项目 between 之间=] 除第一项外的所有项目。那么你不需要测试最后一项。当您删除需要测试最后一项的假设时,一切都会简单得多。所以基本上,我一开始就把问题说错了。感谢大家的回答!
使用 4 个参数调用 reduce 回调:
arr.reduce(callback( accumulator, currentValue, index, array)
示例:
function join(arr, separator) {
if (arr.length === 0) { return(''); }
else {
return (
arr.reduce((accumulator, item, counter) =>
{
if (counter === arr.length - 1) {
return accumulator + item;
} else {
counter += 1;
return accumulator + item + separator;
}
},
'')
);
}
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
您可以通过以下方式缩短代码:
- 跳过空检查 - 如果数组为空,reduce 将 return 初始值 (
''
).
- 使用模板字符串和三元组。如果不是最后一项,则添加分隔符,如果是,则使用空字符串。
- 由于计数器 (
i
) 以 0 开头,您可以跳过第一项的分隔符(0 转换为 false
)。这允许您跳过三元中的比较。
const join = (arr, separator) => arr.reduce((accumulator, item, i) =>
`${accumulator}${i ? separator : ''}${item}`
, '')
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
更改顺序时的另一个想法(基于@JCFord arr[0]
想法),是解构数组,取第一个元素(first
),如果它为空则为其分配默认值.然后减少数组的其余部分,并使用first
作为初始值。
const join = ([first = '', ...arr], separator) =>
arr.reduce((accumulator, item, i) => `${accumulator}${separator}${item}`, first)
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
正如其他人所指出的,您可以在回调中使用索引和数组参数。
但还有另一种方法。您不必知道何时遇到最后一个数组元素。您已经知道第一个元素是什么,您可以直接使用它。
const join = (arr, sep=',') => arr.slice(1).reduce((acc, item) => acc + sep + item, arr[0]);
为了进一步细化函数,利用很少使用的累加器默认初始值。如果你不给reduce()函数传递初始值,第一次执行回调时会得到数组的第一个和第二个元素。
const join = (arr, sep=',') => arr.reduce((acc, item) => acc + sep + item);
并无误地处理空数组...
const join = (arr, sep=',') => arr[0] ? arr.reduce((acc, item) => acc + sep + item) : '';
您可以通过从 reduce
中删除初始值来简化当前函数。然后这将使用第一个元素作为初始值。您已经设置了一个保护子句来处理空数组,因此在这方面您应该没问题。
function join(arr, separator) {
if (arr.length == 0) return '';
return arr.reduce((accumulator, item) => accumulator + separator + item);
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
使用 reduce
join
字符串数组的另一种简单方法是根本不关心它产生的额外分隔符并 slice
在减少数组后将其关闭。
function join(arr, separator) {
return arr.reduce((accumulator, item) => accumulator + separator + item, '')
.slice(separator.length);
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
这是我的做法。
假设您想用逗号分隔此数组,但要以句点结尾。
let names = ['Amber', 'Bobby', 'Chris', 'Dennis', 'Edward'];
您可以使用第三个索引参数“i”,并将其作为变量与被缩减的数组长度进行比较。
names.reduce((a, c, i) => {
const isLast = i == names.length -1;
return `${a}${c}` + (isLast ? '.' : ', ');
}, "")
结果:
'Amber, Bobby, Chris, Dennis, Edward.'
我正在尝试使用 .reduce()
来实现 .join()
的等价物来回答 executeprogram.com 上的测验。我的代码通过了测试,但看起来很难看。我以丑陋的方式解决的具体问题是:构造的 join()
函数将一个数组和一个分隔符作为参数,但是在构造结果连接时,不应在数组的最后一项之后插入分隔符输出。这意味着我必须测试,当用reduce()
遍历数组时,我是否在最后一项(这样我就可以跳过使用分隔符)[哎呀:见下面的注释]。如果数组中有重复值,则使用 indexOf
或 lastIndexOf
不起作用。所以我创建了一个计数器。我不喜欢它。我很乐意提供有关如何更好地做到这一点的建议。这是代码:
function join(arr, separator) {
let counter = 0;
if (arr.length === 0) { return(''); }
else {
return (
arr.reduce((accumulator, item) =>
{
if (counter === arr.length - 1) {
return accumulator + item;
} else {
counter += 1;
return accumulator + item + separator;
}
},
'')
);
}
}
测试及其预期输出如下。同样,上面的函数通过了所有测试,但我认为必须有更好的方法。
> join(['a'], ',')
Expected: 'a'
> join(['a', 'b'], ',')
Expected: 'a,b'
> join(['a', 'b', 'c'], '')
Expected: 'abc'
> join(['a', 'b', 'c', 'd'], 'x')
Expected: 'axbxcxd'
> join(['a', 'b'], 'COMMA')
Expected: 'aCOMMAb'
> join(['', '', ''], ',')
Expected: ',,'
> join([], ',')
Expected: ''
注意:在看到所有有用的答案后,我意识到 真正的 造成这段丑陋代码的原因是我错误的假设分隔符出现在项目“之后”。实际上,分隔符出现在 between 项之间,如果将它插入 before[=33],则可以使它出现在每个项目 between 之间=] 除第一项外的所有项目。那么你不需要测试最后一项。当您删除需要测试最后一项的假设时,一切都会简单得多。所以基本上,我一开始就把问题说错了。感谢大家的回答!
使用 4 个参数调用 reduce 回调:
arr.reduce(callback( accumulator, currentValue, index, array)
示例:
function join(arr, separator) {
if (arr.length === 0) { return(''); }
else {
return (
arr.reduce((accumulator, item, counter) =>
{
if (counter === arr.length - 1) {
return accumulator + item;
} else {
counter += 1;
return accumulator + item + separator;
}
},
'')
);
}
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
您可以通过以下方式缩短代码:
- 跳过空检查 - 如果数组为空,reduce 将 return 初始值 (
''
). - 使用模板字符串和三元组。如果不是最后一项,则添加分隔符,如果是,则使用空字符串。
- 由于计数器 (
i
) 以 0 开头,您可以跳过第一项的分隔符(0 转换为false
)。这允许您跳过三元中的比较。
const join = (arr, separator) => arr.reduce((accumulator, item, i) =>
`${accumulator}${i ? separator : ''}${item}`
, '')
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
更改顺序时的另一个想法(基于@JCFord arr[0]
想法),是解构数组,取第一个元素(first
),如果它为空则为其分配默认值.然后减少数组的其余部分,并使用first
作为初始值。
const join = ([first = '', ...arr], separator) =>
arr.reduce((accumulator, item, i) => `${accumulator}${separator}${item}`, first)
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
正如其他人所指出的,您可以在回调中使用索引和数组参数。
但还有另一种方法。您不必知道何时遇到最后一个数组元素。您已经知道第一个元素是什么,您可以直接使用它。
const join = (arr, sep=',') => arr.slice(1).reduce((acc, item) => acc + sep + item, arr[0]);
为了进一步细化函数,利用很少使用的累加器默认初始值。如果你不给reduce()函数传递初始值,第一次执行回调时会得到数组的第一个和第二个元素。
const join = (arr, sep=',') => arr.reduce((acc, item) => acc + sep + item);
并无误地处理空数组...
const join = (arr, sep=',') => arr[0] ? arr.reduce((acc, item) => acc + sep + item) : '';
您可以通过从 reduce
中删除初始值来简化当前函数。然后这将使用第一个元素作为初始值。您已经设置了一个保护子句来处理空数组,因此在这方面您应该没问题。
function join(arr, separator) {
if (arr.length == 0) return '';
return arr.reduce((accumulator, item) => accumulator + separator + item);
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
使用 reduce
join
字符串数组的另一种简单方法是根本不关心它产生的额外分隔符并 slice
在减少数组后将其关闭。
function join(arr, separator) {
return arr.reduce((accumulator, item) => accumulator + separator + item, '')
.slice(separator.length);
}
console.log(join(['a'], ','))
console.log(join(['a', 'b'], ','))
console.log(join(['a', 'b', 'c'], ''))
console.log(join(['a', 'b', 'c', 'd'], 'x'))
console.log(join(['a', 'b'], 'COMMA'))
console.log(join(['', '', ''], ','))
console.log(join([], ','))
这是我的做法。
假设您想用逗号分隔此数组,但要以句点结尾。
let names = ['Amber', 'Bobby', 'Chris', 'Dennis', 'Edward'];
您可以使用第三个索引参数“i”,并将其作为变量与被缩减的数组长度进行比较。
names.reduce((a, c, i) => {
const isLast = i == names.length -1;
return `${a}${c}` + (isLast ? '.' : ', ');
}, "")
结果:
'Amber, Bobby, Chris, Dennis, Edward.'