javascript 唯一字符串数组,不区分大小写,但保留一个区分大小写的结果
javascript unique string array case insensitive but keep one case sensitive result
这是什么意思?首先让我们看看我写的一些代码:
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"]
这里的目标是使给定的数组不区分大小写,但保留原始输入之一。
我想知道是否有比我想出的解决方案更 elegant/better 执行此问题的解决方案。
在使其唯一之前将整个数组转换为小写不是解决方案,因为我希望最终结果仅包含输入数组中已有的值。哪一个(例如 James
或 james
或 JaMeS
)不相关。
I was wondering if there is a more elegant/better performing solution to this problem than the one I came up with.
使用 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 将维护一个唯一的键列表,因此在构造它时,如果键相同,则先前存储的值将被覆盖。
获得地图后,您可以使用 .values()
迭代值。
有普通对象
您还可以使用在 Chrome、Firefox、Opera 和 Safari 中实现的 Object.fromEntries
method, which at the time of writing, is a stage 4 proposal (Draft ES2020):
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = Object.fromEntries(names.map(s => [s.toLowerCase(), s]));
console.log(Object.values(uNames));
如您所见,方法非常相似。
第一次出现&原始顺序
以上将收集 last 出现,按 first 出现的顺序。
如果你想收集第次出现,你可以先反转输入,然后按上面的方法继续。然后输出将收集 first occurrence,顺序为 last occurrence.
如果你真的需要 first 出现的顺序 first 出现,你可以使用 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()]);
如果要对字符串数组进行重复数据删除,优先考虑第一次出现的情况,并保持插入顺序,请使用此方法。
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));
这是什么意思?首先让我们看看我写的一些代码:
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"]
这里的目标是使给定的数组不区分大小写,但保留原始输入之一。
我想知道是否有比我想出的解决方案更 elegant/better 执行此问题的解决方案。
在使其唯一之前将整个数组转换为小写不是解决方案,因为我希望最终结果仅包含输入数组中已有的值。哪一个(例如 James
或 james
或 JaMeS
)不相关。
I was wondering if there is a more elegant/better performing solution to this problem than the one I came up with.
使用 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 将维护一个唯一的键列表,因此在构造它时,如果键相同,则先前存储的值将被覆盖。
获得地图后,您可以使用 .values()
迭代值。
有普通对象
您还可以使用在 Chrome、Firefox、Opera 和 Safari 中实现的 Object.fromEntries
method, which at the time of writing, is a stage 4 proposal (Draft ES2020):
let names = ['James', 'james', 'bob', 'JaMeS', 'Bob'];
let uNames = Object.fromEntries(names.map(s => [s.toLowerCase(), s]));
console.log(Object.values(uNames));
如您所见,方法非常相似。
第一次出现&原始顺序
以上将收集 last 出现,按 first 出现的顺序。
如果你想收集第次出现,你可以先反转输入,然后按上面的方法继续。然后输出将收集 first occurrence,顺序为 last occurrence.
如果你真的需要 first 出现的顺序 first 出现,你可以使用 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()]);
如果要对字符串数组进行重复数据删除,优先考虑第一次出现的情况,并保持插入顺序,请使用此方法。
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));