[codewars 译解注] Isograms

题目简介

isogram[1] 是指一个没有重复字母的词, 无论连续还是非连续. 实现一个函数, 该函数确定只包含字母的字符串是否是 isogram. 假设空字符串是 isogram. 忽略字母大小写.

isIsogram( "Dermatoglyphics" ) == true
isIsogram( "aba" ) == false
isIsogram( "moOse" ) == false // -- 忽略字母大小写
1
2
3

解注

Part 1

首先来看看我的实现

function isIsogram(str){
    // 这里用于 "假设空字符串是 isogram"
    if (!str) return true;

    // "忽略字母大小写", 因此将其全部转为小写
    str = str.toLocaleLowerCase();

    /**
     * 以下为核心部分
     * 1. 遍历字符串的每个字符
     * 2. 将当前字符其存入栈中
     * 3. 在存入栈前, 判断栈中是否存在该字符
     */
    const tmp = [];

    for (let index = 0; index < str.length; index++) {
        const element = str[index];
        if (tmp.indexOf(element) === -1) {
            tmp.push(element);
        } else {
            return false;
        }
    }
    return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Part 2

有没有更巧妙的方式呢, 来看以下这个 Best Practices 的第一名[2]

function isIsogram(str){ 
  return !/(\w).*\1/i.test(str)
}
1
2
3

用到了我暂时还不擅长的正则表达式, 那我们就来研究一下吧

  • /.../i 表达式的结尾处的不区分大小写 i 标记指定不区分大小写.
  • \w 匹配字母或数字或下划线或汉字 等价于 [^A-Za-z0-9_].
  • a.*b 它将会匹配最长的以a开始,以b结束的字符串.
  • \1 指定第一个子匹配项.

因此就是匹配两个相同字符之间的字符串.

Part 3

既然正则不熟, 我们再找找. 看, 这个:

function isIsogram(str){
  return new Set(str.toUpperCase()).size == str.length;
}
1
2
3

是使用了 es6+ 中出现的 Set.

Set[3] 对象是值的集合,你可以按照插入的顺序迭代它的元素。 Set中的元素只会出现一次,即 Set 中的元素是唯一的。

拍手称赞.

总结

这是一道很简单的题, 前端初学者基本上都能像我一样写出答案, 但是看过别人更巧妙的解答, 你有学到什么吗?


  1. isograms: 直译为 "等值线图". 在维基百科中明确其含义为与本题目一致, 用于地理和制图术语时可以参阅 contour line. ↩︎

  2. 排名截止到当前文章编辑时间, 后续可能会发生变更. ↩︎

  3. 查看 MDN 中 Set 的文档 ↩︎