Home > Blockchain >  Insert item between every other item in array similar to Array.join
Insert item between every other item in array similar to Array.join

Time:08-25

Array.join is useful because it glues together an array of strings by a delimiter taking into account empty arrays and not padding the delimiter at either end of the output string.

I am making a React application and I would like find a similar native function, however, my array of React.ReactNode elements is going to be mapped and rendered, so instead of joining the array with a delimiter and outputting a string, I just want to join the array with a string delimiter, but maintain the Array structure. Is there something already native to javascript/typescript/react that I can use to achieve the below psuedo-code?

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>
    ))}
  </>
)

CodePudding user response:

You could use reduce without the initialValue argument:

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

This requires special care when a is an empty array. If that needs to be supported, then:

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

CodePudding user response:

Welp, kind of answered my own question. Currently, I use the following function to achieve this:

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

Example:

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, '|'));
/// [{...}, '|', {...}, '|', {...}]

CodePudding user response:

You could try this solution:

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, '|'));

  • Related