Разбить строку в массив с условиями, используя array.reduce

#javascript #arrays

#javascript #массивы

Вопрос:

Я хочу разбить строку на массив с максимальным количеством символов 15 на элемент в массиве. Я хочу выполнить это с array.reduce помощью . Может кто-нибудь указать мне правильное направление?

Глядя на это:

 const str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit'
  

Я хочу получить такой результат:

 const result = ['Lorem ipsum', 'dolor sit amet', 'consectetur', 'adipiscing elit']
  

Комментарии:

1. ну, попробуйте на самом деле использовать array reduce

2. почему reduce ? звучит слишком сложно

3. const result = str.split(' ').reduce((a,i)=>(a.length?(()=>{let n=a.length-1,s=a[n],l=s.length;((s i).length<15)?a[n] =' ' i:a.push(i)})():a.push(i),a),[]);

4. Для записи также возможно с регулярным выражением. Однако очень не рекомендуется — я просто сделал это для развлечения: /(?<=^|s).{1,15}(?=s|$)/g сопоставьте до 15 символов, но они должны быть целыми словами, поэтому они не будут соответствовать середине слова и не будут содержать пробел перед / после слова. [...str.matchAll(regex)].flat() выдает ожидаемый результат.

Ответ №1:

Для каждой reduce итерации объединяйте с последним предложением, а затем сравнивайте длину с максимальной, если она превышает, добавьте новое предложение, иначе замените последнее предложение объединенным

 const str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit'

const res = str.split(' ').reduce((acc, word) => {
  const lastSentence = acc.pop()
  const currentConcatnated = [lastSentence, word].filter(Boolean).join(' ')
  
  if (currentConcatnated.length > 15) {
    acc.push(lastSentence)
    acc.push(word)
  } else {
    acc.push(currentConcatnated)
  }
  
  return acc
}, [])

console.log(res)  

Комментарии:

1. Вот и все, спасибо! По какой-то причине мне было трудно понять, что такое Reduce.

2. @zero мне тоже сложно в первый раз, главное, что я убрал после долгой практики, — не забывать возвращать накопленное значение после каждой итерации

Ответ №2:

Вот более понятный подход, который все еще используется Array.prototype.reduce() . Это позволяет избежать доступа к последнему элементу, acc если он пуст, утверждая lastIndex >= 0 , что это не первая итерация.

 const str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit';
const result = str.split(' ').reduce((acc, cur) => {
  const lastIndex = acc.length - 1;
  const val = ' '   cur;

  if (lastIndex >= 0 amp;amp; acc[lastIndex].length   val.length <= 15) {
    acc[lastIndex]  = val;
  } else {
    acc.push(cur);
  }

  return acc;
}, []);

console.log(result);  

Ответ №3:

Это еще одна реализация, использующая альтернативные приемы. Array#reduce

  • Оператор объединения ?? с нулевым значением для дополнительной безопасности.
  • Array#concat , поэтому никогда не изменяет аргумент массива. Это не обязательно, но это полезный трюк для других ситуаций, когда мутации нецелесообразны.

 const str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit';

const result = str.split(/s /); //split on any amount of whitespace
  .reduce((acc, word) => {
    //get the last item but start with an empty string if `acc` is empty
    const last = acc[acc.length - 1] ?? "";
    
    //construct the potential new entry and remove extra spaces from start/end
    const newLast = `${last} ${word}`.trim();
    
    if (newLast.length > 15) //if too long
      return acc.concat(word);    // just add the word as a new element
    
    return acc.slice(0, -1) //take everything but the last item
      .concat(newLast); //append the new element as last
  }, []);
  
console.log(result);  

Кроме того, альтернативная реализация может быть выполнена просто с использованием регулярного выражения

 /(?<=^|s)b.{1,15}b(?=s|$)/g
  

Это будет соответствовать до 15 символов, если они образуют целые слова, поэтому они не будут соответствовать середине слова или пробелам до или после слов.

 const regex = /(?<=^|s)b.{1,15}b(?=s|$)/g;

const str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit';

const result = [...str.matchAll(regex)].flat();

console.log(result);  

Смотрите на Regex101

Вот несколько примеров того, почему это работает:

 Lorem ipsum dolor sit amet consectetur adipiscing elit
^         ^^  ^
|_________||  |
    11     |  |
           |  |
           |    -> the 15th character but the next symbol is not whitespace or the end of the line, so the match cannot end here
             -> whitespace so the match cannot end here 
  
 Lorem ipsum dolor sit amet consectetur adipiscing elit
           ^^            ^
           ||____________|
           |      14
           |
             -> the match cannot start on a whitespace and it also has to be preceded by whitespace