在数组中类似于array.join的每个其他项之间插入项



Array.join非常有用,因为它通过一个分隔符将字符串数组粘合在一起,同时考虑到空数组,并且不填充输出字符串两端的分隔符。

我正在制作一个React应用程序,我想找到一个类似的本地函数,然而,我的React.ReactNode元素数组将被映射和渲染,所以我不想用分隔符连接数组并输出字符串,我只想用字符串分隔符连接阵列,但要保持array结构。javascript/typescript/rect是否已经有一些原生的东西可以用来实现下面的psuedo代码?

let parts: React.ReactNode[] = [];
if (conditionA) {
parts.push(<div>Component One</div>);
}
if (conditionB) {
parts.push(<div>Component Two</div>);
}
parts = joinByDelimiterButKeepAsArray(parts, '|');
// I wants parts to now equal
// [<div>Component One</div>, '|', <div>Component Two</div>]
// if conditionA and conditionB are both true
return (
<>
{parts.map((part, i) => return (
<React.ReactFragment key={i}>{part}</React.ReactFragment>
))}
</>
)

您可以在不使用initialValue参数的情况下使用reduce

a.reduce((acc, val) => [].concat(acc, delimiter, val));

a是空数组时,这需要特别小心。如果需要支持,那么:

a.length ? a.reduce((acc, val) => [].concat(acc, delimiter, val)) : a;

附录

我刚刚发现,当reduce将返回与数组元素相同的类型时,TypeScript只允许省略reduce的第二个参数。在这里,我们想要返回一个不同的类型(T[]而不是T(,但从一个隐含的T初始值开始。不可能。

因此,这个限制扼杀了上述JavaScript解决方案的美丽,因为现在我们必须提供第二个参数:

a.reduce<T[]>((acc, val) => acc.concat(delimiter, val), []).slice(1);

以及回调参数的附加类型规范:

a.reduce<T[]>((acc: T[], val: T) => acc.concat(delimiter, val), []).slice(1);

您可以尝试以下解决方案:

const parts = ['<div>Component One</div>', '<div>Component Two</div>'];
/**
* Add the delimiter between each item in the array.
*
* @param {any[]} array
* @param {string} delimiter
* @returns {any[]}
*/
const joinByDelimiterButKeepAsArray = (array, delimiter) => {
/**
* To prevent the function from crashing, we need to check if the array is an array.
*/
if (!Array.isArray(array) || array.length === 0) {
return [];
}
const [firstElement, ...rest] = array;
return rest.reduce((acc, curr) =>
acc.concat(delimiter, curr)
/**
* The initialValue is set to an array containing the first element of the array to
* prevent the edge case of an array of length 1. If we don't do this, it would result
* in an array of length 2 with the first element being the first element of the array
* and the second element being the delimiter.
*
* e.g. [onlyOneElement] -> [onlyOneElement, delimiter]
*/
, [firstElement]);
};
console.log(joinByDelimiterButKeepAsArray(parts, '|'));

更新

我以前从未用过打字。键入内容可能如下所示:

const joinByDelimiterButKeepAsArray: <T>(array: T[], delimiter: T) => T[] = (array: T[], delimiter: T): T[] => {
if (!Array.isArray(array) || array.length === 0) {
return [];
}
const [firstElement, ...rest] = array;
return rest.reduce((acc: T[], curr: any): T[] =>
acc.concat(delimiter, curr)
, [firstElement]);
};

如果有帮助,请考虑将其标记为答案!

好吧,有点回答了我自己的问题。目前,我使用以下功能来实现这一点:

function joinByDelimiterButKeepAsArray<T>(a: T[], delimiter: T): T[] {
return a.flatMap((n, i) => (i + 1 < a.length ? [n, delimiter] : [n]));
}

示例:

const parts: React.ReactNode[] = [];
parts.push(<div>Component One</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}]
parts.push(<div>Component Two</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}, '|', {...}]
parts.push(<div>Component Three</div>);
console.log(joinByDelimiterButKeepAsArray(parts, '|'));
/// [{...}, '|', {...}, '|', {...}]

最新更新