Это нормально использовать для цикла в строке? - PullRequest
2 голосов
/ 26 сентября 2019

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

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

function firstNonRepeatingLetter(str) {
  const lowerStr = str.toLowerCase();

  for (let char in lowerStr) {
    if (lowerStr.lastIndexOf(lowerStr[char]) === parseInt(char) && 
    lowerStr.indexOf(lowerStr[char]) === parseInt(char)) {
      return str[char];
    }
  }

  return "";
}

Напишите функцию с именем first_non_repeating_letter, которая принимает на вход string и возвращает первый символ, который не являетсяповторяется в любом месте строки.

Примеры:

firstNonRepeatingLetter('a') => 'a'
firstNonRepeatingLetter('stress') => 't'
firstNonRepeatingLetter('sTreSS') => 'T'

Ответы [ 6 ]

4 голосов
/ 26 сентября 2019

Пока ваш код работает, я предлагаю взять индекс для итерации символов строки.

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

В другом цикле сравните фактический индекс с сохраненным индексом для того же символа и верните, если он равен.

function firstNonRepeatingLetter(str) {
    var lowerStr = str.toLowerCase(),
        hash = {},
        i;

    for (i = 0; i < lowerStr.length; i++)
        hash[lowerStr[i]] = i;

    for (i = 0; i < lowerStr.length; i++)
        if (hash[lowerStr[i]] === i)
            return str[i];

    return "";
}

console.log(firstNonRepeatingLetter('a'));      // a
console.log(firstNonRepeatingLetter('stress')); // t
console.log(firstNonRepeatingLetter('sTreSS')); // T
2 голосов
/ 27 сентября 2019

Чтобы ответить на вопрос, да, вы можете использовать for..in со строками.Правда, в большинстве случаев вы не должны.

for(i in X) работает следующим образом:

  • , если X не является объектом, преобразуйте его в соответствующую оболочку (aчисло для Number, строка для String)
  • для каждого "перечисляемого свойства" X, присвойте его имя i и запустите тело цикла

Строки преобразуются в String объекты, и, как вы можете видеть в консоли, они похожи на массивы: они имеют числовые свойства от 0 до длины - 1, и каждое свойство содержит соответствующий символ:

enter image description here

То есть, приведенная выше логика прекрасно работает со строками.

Однако, если вы хотите итерировать только строку char-by-char, есть более прямой способ сделать то же самое: цикл for..of.

for(a of X) выбирает каждый элемент (не свойство) из X (который может быть строкой, массивом или любым «итерируемым» объектом) и присваивает его «a».С for..of ваш код может быть изменен следующим образом:

function firstNonRepeatingLetter(str) {
    const lowerStr = str.toLowerCase();

    for (let char of lowerStr) {
        if (lowerStr.lastIndexOf(char) === lowerStr.indexOf(char))
            return char;
    }

    return "";
}
1 голос
/ 27 сентября 2019

Чтобы ответить на вопрос в заголовке, оператор for..in предназначен для итерации перечисляемых свойств объекта (включая элементы в цепочке прототипов).Хотя он «работает» на итерируемых типах, обычно не рекомендуется использовать его в качестве метода итерации массивоподобных структур, поскольку он может дать неожиданные результаты, когда вы обычно просматриваете только числовые индексы.

Например, представьте, что вы позже используете функциональность polyfill или иным образом измените прототип String.

String.prototype.polyfill = () => {}
for(const prop in 'abc')
    console.log(prop)

Редактировать: О, хватит.Похоже, двое из нас попали туда одновременно.Я также отмечу, что регулярные выражения хороши для решения такого рода проблем. регулярное выражение 101

const firstNonRepeatingLetter = str => 
    (str && /(.)(?!.*?\1)/i.exec(str)[0]) || ''
    
;[
    'a',
    'stress',
    'sTreSS'
]
    .forEach(
        str => console.log(firstNonRepeatingLetter(str))
    )
1 голос
/ 27 сентября 2019

Как насчет использования двух массивов?Во-первых, вы можете создать массив, используя split, а также создать обратный массив.

const origin = str.split('');
const reverse = [...origin].reverse();

Затем вы можете использовать filter.

const nonRepeats = origin.filter((ele, index) => ele !== reverse[index]);
return nonRepeats[0];
1 голос
/ 26 сентября 2019

Алгоритмический подход с использованием javascript maps: И да, прекрасно использовать for loops со строками.

const fn = (str) => {
  res = [];
  var ch = new Map();
  for(var i = 0; i<str.length; i++) {
    if(ch.has(str[i])) {
      var val = ch.get(str[i])
      val += 1
      ch.set(str[i],val)
    } else {
      ch.set(str[i], 1)
    }
  }
  ch.forEach((val, key) => {
    if(val == 1) {
      res.push(key)
    }
  })
  return res[0]
}

console.log(fn('abcdeabcdef'))
0 голосов
/ 26 сентября 2019

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

Вернемся к вопросу - вы можете преобразовать строку вмассив с помощью метода .split().Массив предоставляет ряд полезных методов, таких как .filter(), .map() и т. Д., Которые можно использовать вместо for loop.

...