Я считаю, что @ggorlen имеет подходящее решение, хотя он использует довольно современный JavaScript (я не видел синтаксиса до использования обратных тиков вместо скобок для вызова функций, но я верю, что это работает в некоторых интерпретаторах)
Для более простого ответа «старой школы» попробуйте что-то вроде следующего:
var input = "AbCyTtaCc113";
var output = "";
var unique = {};
for (var i = 0; i < input.length; i++) {
if (!unique[input[i].toLowerCase()]) {
unique[input[i].toLowerCase()] = 1;
output += input[i];
}
}
Второе обновление
Приведенное ниже решение ES6 было сохранено для исторических целей, но@ggorlen указал, что мне не удалось сохранить корпус на выходе.Поэтому преобразование в нижний регистр должно происходить только при проверке фильтра, а не ранее:
var input = "AbCyTtaCc113";
var seen = new Set();
var output = input
.split("")
.filter(x => !seen.has(x.toLowerCase()) && seen.add(x.toLowerCase()))
.join("")
Обновление
Поскольку всем нравится писать ответы на ES6 и пытаться решить эту проблему с помощью reduce
илиmap
или Set
или какой-либо другой подобный инструмент, позвольте мне написать, как я думаю, ответ лучший с использованием ES6:
var input = "AbCyTtaCc113";
var seen = new Set();
var output = input
.split("")
.map(x => x.toLowerCase())
.filter(x => !seen.has(x) && seen.add(x))
.join("")
Или, есливы предпочитаете нечитаемую чепуху в одну строку:
var input = "AbCyTtaCc113";
var seen = new Set(), output = input.split("").map(x => x.toLowerCase()).filter(x => !seen.has(x) && seen.add(x)).join("");
Я предпочитаю это решение, потому что:
- В нем используется цепочка методов для передачи нашего ввода через ряд простых преобразований, которые легкочитать и интерпретировать будущие программисты (сначала разделить, затем отобразить, затем отфильтровать, затем объединить)
- Избегает синтаксиса, который не поддерживается во многих интерпретаторах JavaScript (без операторов распространения, обратных тиков и т. д.)
- Он использует каждый метод для своей семантической цели (split преобразует строку в массив, map изменяет каждое значение массива, фильтр выбирает подмножество массива, join преобразовывает массив в строку)
Тем не менее, если производительность является вашей главной задачей, и вы запускаете ее в консоли Google Chrome, я должен признать, что предварительные тесты оценивают ответ Джонаса Вильма как более быстрый, чем мой:
var d0 = new Date(); for (var i = 0; i < 50000; i++) {
var input = "AbCyTtaCc113";
var output = [...input].filter((s => c => !s.has(c.toLowerCase()) && s.add(c.toLowerCase()))(new Set)).join("");
} console.log(new Date() - d0);
// ~175
var d0 = new Date(); for (var i = 0; i < 50000; i++) {
var input = "AbCyTtaCc113";
var seen = new Set();
var output = input
.split("")
.map(x => x.toLowerCase())
.filter(x => !seen.has(x) && seen.add(x))
.join("");
} console.log(new Date() - d0);
// ~231
Я полагаю, это потому, что .map()
выделяет новый массив в памяти, а не модифицирует массив на месте (тогда как его решение, использующее .toLowerCase()
в .has()
, изменяет значения на месте, поэтому не использует дополнительную память), но я предпочитаю это для ясности.Если вы не имеете дело с кодом, где производительность имеет первостепенное значение, я думаю, что возможность читать код важнее, чем выделять лишнюю миллисекунду.