В прошлый раз мы изучили, как разбить проблему на более мелкие задачи, чтобы найти решение: теперь давайте проведем рефакторинг нашего решения и рассмотрим стратегии, которые могут помочь нам понять как наш код, так и язык программирования, который мы используем.

В прошлый раз проблема заключалась в том, чтобы взять строку и манипулировать ею так, чтобы каждый символ в строке был написан с заглавной буквы и повторялся в соответствии с их позицией индекса.

function repeat(string)repeat("abcd") -> "A-Bb-Ccc-Dddd"
repeat("RqaEzty") -> "R-Qq-Aaa-Eeee-Zzzzz-Tttttt-Yyyyyyy"
repeat("cwAt") -> "C-Ww-Aaa-Tttt"

Я придумал следующее решение:

const string = "abcde";
dupCharByIndex = (s) =>{
  const chars = s.split('');
  return chars.map((char,index)=>{
    return char.toLowerCase().repeat(index + 1);
  });
};
function capAndHyphenArray(s){
  const chars = dupCharByIndex(s);
  return chars.map(char => {
    if (char.length !== 1){
      const charArray = char.split('');
      const cap = charArray[0].toUpperCase();
      const hyphen = "-";
      charArray.shift();
      charArray.unshift(hyphen + cap);
      return charArray.join('');
     } else {
        return char.toUpperCase();
        };
   }).join('');
 };
capAndHyphenArray(string)
//A-Bb-Ccc-Dddd-Eeeee

В этом решении много чего происходит, поэтому давайте попробуем найти способы сделать решение более эффективным и упростить код, чтобы его было легче читать. Во-первых, давайте начнем с рассмотрения большой буквы О. При этом мы должны искать, где с нашим решением приходится работать больше всего. Должно ли решение перебирать данные, и если да, то есть ли внутри вложенные итерации? Для этого решения у нас есть пара итераций, но нет вложенных итераций, делающих решение O (n)

dupCharByIndex(string)
  chars.map((char,index)
capAndHyphenArray(s)
const chars = dupCharByIndex(s);
chars.map(char => {
if (char.length !== 1){
      const charArray = char.split('');

Наше решение имеет вложенную итерацию в функции capAndHyphenArray. Мы отображаем символы, а затем для каждого символа, длина которого не равна 1, мы разделяем символы. Это делает нашу функцию очень дорогой с точки зрения затрат памяти. Таким образом структурируя функции, мы заставляем компьютер выполнять массу работы. Возьмите эту строку, разделите ее, повторите каждый символ по его индексу, затем возьмите эту новую строку, и если строка длиннее одной, разделите ее также на массив. Из-за вложенного итератора у нас есть решение O (n²). Как мы можем сделать это более эффективным?

При поиске способа сделать решение более эффективным следует учитывать противоположное тому, о чем мы думали, когда изначально пытались решить проблему. Какие задачи мы можем объединить или упростить? Начнем с dupCharByIndex (строка).

dupCharByIndex = (s) =>{
  const chars = s.split('');
  return chars.map((char,index)=>{
    return char.toLowerCase().repeat(index + 1);
  });
};

Что здесь можно сделать, чтобы упростить это? Поговорим об операторе спреда.

моя переменная chars - хорошая ссылка, но мы можем преобразовать эту переменную в строку .map () с помощью оператора распространения

const chars = s.split(''); is equivalent to: [...s];

поэтому вместо того, чтобы моя функция задавала переменную, а затем вызывала ее, мы можем упростить ее как таковую:

dupCharByIndex = (s) =>{
   return [...s].map((char,index)=>{
   /// etc...

Это может показаться не таким уж большим делом, но исключение строк кода окупится, когда вы работаете с файлами, состоящими из сотен, если не тысяч, если не десятков тысяч строк.

Пока мы говорим об упрощении, давайте рассмотрим роль dupCharByIndex. Мы знаем, что используем его в нашей функции capAndHyphenArray, поэтому вместо повторного вызова, сделав его переменной, давайте просто сделаем это в функции capAndHyphenArray. Кроме того, давайте изменим имя функции, поскольку она будет выполнять другую работу.

Старый:

function capAndHyphenArray(s){
  const chars = dupCharByIndex(s);
  return chars.map(char => {
    if (char.length !== 1){
      const charArray = char.split('');
// etc...

Новый:

function repeatCharByIndex(s){
  return [...s].map((char,index)=>{
      return char.toLowerCase().repeat(index + 1)

Давайте сделаем еще один шаг, вот остальная часть логики моей старой функции capAndHyphen:

return chars.map(char => {
    if (char.length !== 1){
      const charArray = char.split('');
      const cap = charArray[0].toUpperCase();
      const hyphen = "-";
      charArray.shift();
      charArray.unshift(hyphen + cap);
      return charArray.join('');
     } else {
        return char.toUpperCase();
        };
   }).join('');

Давайте сделаем это более эффективным, взяв задачу повторения символов, а также объединим ее с нашей задачей использования заглавных букв и нашей задачей добавления дефиса:

function repeatCharByIndex(s) {
  return [...s].map((element, index) => {
    return element.toUpperCase() + element.toLowerCase().repeat(index);
  }).join('-');
}

Здесь мы возвращаем элемент в s (char), пишем его заглавными буквами, а затем добавляем дополнительный элемент в нижнем регистре и повторяем его на основе его индекса. Теперь мы устранили вложенную итерацию и превратили эту функцию из O (n²) в O (n):

const string = "abcde";
dupCharByIndex = (s) =>{
  const chars = s.split('');
  return chars.map((char,index)=>{
    return char.toLowerCase().repeat(index + 1);
  });
};
function capAndHyphenArray(s){
  const chars = dupCharByIndex(s);
  return chars.map(char => {
    if (char.length !== 1){
      const charArray = char.split('');
      const cap = charArray[0].toUpperCase();
      const hyphen = "-";
      charArray.shift();
      charArray.unshift(hyphen + cap);
      return charArray.join('');
     } else {
        return char.toUpperCase();
        };
   }).join('');
 };
capAndHyphenArray(string)
//A-Bb-Ccc-Dddd-Eeeee

в это:

const string = "abcde";
function repeatCharByIndex(s) {
  return [...s].map((element, index) => {
    return element.toUpperCase() + element.toLowerCase().repeat(index);
  }).join('-');
}
repeatCharByIndex(string)
//A-Bb-Ccc-Dddd-Eeeee

На этом все, но по мере того, как я продолжаю работать над более сложными проблемами, обязательно напишу еще один пост, посвященный более продвинутым концепциям и решениям.