JavaScript不重复字符串数组(大小写不敏感),但保留一个区分大小写的结果。

4

我是什么意思呢?首先让我们看一下我写的一些代码:

  let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
  let uNames = {};

  names.forEach(n => {
    let lower = n.toLowerCase();
    if (!uNames[lower]) {
      uNames[lower] = n;
    }
  });

  names = Object.values(uNames);
  console.log(names); // >>> (2) ["James", "bob"]

目标是忽略大小写,但保留一个原始输入,使数组中的值唯一。

我在想是否有比我提出的更优雅/性能更好的解决方案。

仅将整个数组转换为小写字母后再进行去重不是一个解决方案,因为我希望最终结果只包含已经存在于输入数组中的值。无论哪个输入(例如 JamesjamesJaMeS)都不重要。


2
请查看Array.prototype.map使用Set的此答案的组合。 - JJWesterkamp
2个回答

10

我在想是否有比我想出的更优雅/性能更好的解决方案。

使用一个 Map

let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = new Map(names.map(s => [s.toLowerCase(), s]));

console.log([...uNames.values()]); 

Map的构造函数可以接受一组键值对数组(嵌套数组,包含2个值:键和值)。Map将维护一个唯一的键列表,因此如果键相同,则在构建时先前存储的值将被覆盖。

一旦有了Map,就可以使用.values()迭代值。

使用普通对象

您还可以使用Object.fromEntries方法,在撰写本文时,该方法是ES2020草案第4阶段(Draft ES2020),已在Chrome、Firefox、Opera和Safari中实现:

let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = Object.fromEntries(names.map(s => [s.toLowerCase(), s]));

console.log(Object.values(uNames)); 

如您所见,这种方法非常相似。
第一次出现和原始顺序
以上将收集最后出现的内容,按首次出现的顺序排列。
如果您想要收集第一次出现的内容,只需先反转输入,然后继续操作如上。然后输出将已经收集第一次出现的内容,并按最后出现的顺序排列。
如果您确实需要按首次出现的顺序收集第一次出现的内容,则可以使用reduce,如下所示:

let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = names.map(s => s.toLowerCase()).reduce((map, s, i) => 
    map.get(s) ? map : map.set(s, names[i])
, new Map);

console.log([...uNames.values()]); 


使用Map和对象有什么区别? - Ayush Gupta
1
据我理解,这个映射的作用是确保输出数组包含实际的输入字符串,而不是它们的小写变体。 - JJWesterkamp
你可以使用对象属性做同样的事情,但是 Map 有这个有用的构造函数并且易于迭代。在我看来更加优雅。但这只是一个观点。 - trincot
但是这里有一个警告。如果原始数组具有数字字符串,则Object.values不会保留元素顺序(插入顺序)。如果您需要保持顺序不变,请使用Map - Константин Ван
@trincot 您不能简单地执行 names.reverse()[...uNames.values()].reverse() 来获取第一次出现 保持正确的顺序。对于 names = ["bOB", "james", "bob", "JaMeS", "Bob"],如果您使用 reverse() 和再次 reverse() 的方法,您会得到 ["james", "bOB"] 而不是 ["bOB","james"] - Константин Ван
显示剩余6条评论

0
如果您想对一个字符串数组进行去重,优先保留第一次出现的元素,并且保持插入顺序,请使用以下代码。

const a = ["ALPHA", "10", "BETA", "10", "alpha", "beta", "aLphA"];
const b = ["3", "1", "2", "2", "3", "1"];

function dedupe(string_array) {
 const entries = string_array
  .slice()
  .reverse()
  .map((string, index) => [
   string.toLowerCase(),
   {
    string,
    index: string_array.length - 1 - index
   }
  ]);
 const case_insensitively_deduped_string_array = Array
  .from((new Map(entries)).values())
  .sort((a, b) => (a.index - b.index))
  .map(item => item.string);
 return case_insensitively_deduped_string_array;
 // Takes the first occurrences, keeping the insertion order.
 // Doesn’t modify the input array.
}

console.log(a, dedupe(a));
console.log(b, dedupe(b));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接