JavaScript方法从字符串/数字中删除不区分大小写的重复项

时间:2019-05-08 20:58:20

标签: javascript ecmascript-6

寻找一种干净的方法来删除重复项,并与发现的重复编号/字母的第一次出现保持一致

假设我有一个字符串

AbCyTtaCc113

我想要剩下的是

AbCyT13

4 个答案:

答案 0 :(得分:4)

  [...input].filter((s => c => !s.has(c.toLowerCase()) && s.add(c.toLowerCase()))(new Set)).join("")

散布字符串会导致一个包含一个字符串的数组,通过使用Set,您可以轻松过滤出重复项。逻辑基本上是:

  • 通过扩展([...input])将字符串转换为字符数组。

  • 创建一个Set并将其作为s存储在闭包内部。 ((s => ...)(new Set)

  • 如果...则过滤掉字符

    • 角色已经在集合中(!s.has(c.toLowerCase())

    • 如果不是,请将其添加到集合中并保留(&& s.add(c.toLowerCase())

  • 通过联接将过滤后的数组变回字符串。

或不区分大小写的版本:

[...new Set(input)].join("")

命令版本为:

  let result = "";
  {
     const duplicates = new Set();
     for(const char of input) {
        if(!duplicates.has(char.toLowerCase()) {
          duplicates.add(char.toLowerCase());
          result += char;
        }
     }
  }

答案 1 :(得分:0)

这不需要ES6,在这种情况下,它不会使其更快,也不会更干净。走路一次并减少:

"AbCyTtaCc113"
.split("")
.reduce((ac,d)=>{!~ac.toLowerCase().indexOf(d.toLowerCase()) && (ac += d); return ac;},"")

答案 2 :(得分:-1)

使用Array.prototype.reduce是解决此问题的一种方法。

编辑:正如其他人所提到的,虽然没有将其用于生产级解决方案,但有充分的理由。因此,将其作为一种可能,尽管不是明智的方式。

console.log(
  [..."AbCyTtaCc113"]
    .reduce(
      (acc, val) => 
        acc.includes(val.toUpperCase()) || acc.includes(val.toLowerCase())
          ? acc 
          : [...acc, val]
        , []
    )
    .join("")
)

答案 3 :(得分:-1)

我相信@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答案并尝试用reducemapSet或其他类似工具来解决这个问题,所以让我写一下我认为的 最佳 答案:

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("");

我更喜欢这种解决方案,因为:

  1. 它利用方法链将我们的输入通过一系列简单的转换,以便将来的程序员可以轻松读取和解释(首先拆分,然后映射,然后过滤,然后加入)
  2. 它避免了许多JavaScript解释器不支持的语法(没有扩展运算符,反引号等)
  3. 它出于语义目的使用每种方法(拆分将字符串转换为数组,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()的解决方案修改了这些值,因此不使用额外的内存),但是为了清楚起见,我更喜欢这样做。除非您要处理性能是最重要的代码,否则我认为能够读取代码比花费额外的毫秒时间更重要。