以下代码应采用对象数组和这些对象的键列表,并返回表示该组键的不同值的对象数组。我假设这些键的属性类型只有string、number 或boolean。
function distinct<T extends Record<K, string | number | boolean>,
K extends keyof T>(arr: T[], ...keys: K[]): Pick<T, K>[] {
const key = (obj: T) => JSON.stringify(keys.map(k => obj[k]));
const val = (obj: T) => keys.reduce((a, k) => (a[k] = obj[k], a), {} as Pick<T, K>);
const dict = arr.reduce((a, t) => (a[key(t)] = val(t), a), {} as { [k: string]: Pick<T, K> })
return Object.values(dict);
}
我们的想法是获取数组中的每个对象,用JSON.stringify() 序列化它的属性元组,并将这个序列化的字符串用作字典键。我们在该键上放置的值是一个仅由这些属性的值组成的对象。通过使用字典,我们保证在我们关心的键上,每组不同的属性只会出现一个对象。然后我们把这个字典的值变成一个数组。
如果我在您的 myObject 示例上对其进行测试,结果如下:
const result = distinct(myObject, "country", "state");
console.log(result);
/* [{ "country": "USA", "state": "Missouri" }, { "country": "Canada", "state": "Alberta" }] */
这就是你想要的。让我们也测试一下我现在编写的一些类型和数组:
interface MyObject {
country: string,
state: string,
age: number,
name: string
}
const arr: MyObject[] = [
{ name: "Alice", age: 35, country: "USA", state: "MA" },
{ name: "Bob", age: 40, country: "USA", state: "MI" },
{ name: "Carmen", age: 35, country: "Mexico", state: "BC" },
{ name: "Danilo", age: 35, country: "Mexico", state: "MI" }
]
所以我们有一个MyObject 数组。让我们获取不同的 country 值:
const distinctCountries = distinct(arr, "country"); // Array<{country: string}>
console.log(distinctCountries); // [{ "country": "USA" }, { "country": "Mexico" }]
console.log(distinctCountries.map(x => x.country)); // USA, Mexico
注意结果是一个{country: string} 值的数组。您可以使用map() 将其转换为strings 的数组。让我们得到不同的 country 和 state 值:
const distinctCountriesAndStates = distinct(arr, "country", "state");
console.log(distinctCountriesAndStates);
/* [{ "country": "USA", "state": "MA" }, { "country": "USA", "state": "MI" },
{ "country": "Mexico", "state": "BC" }, { "country": "Mexico", "state": "MI" }] */
这里是{country: string, state: string} 对象的数组。不确定您想如何表示它们,但您可以使用map() 来按您认为合适的方式按摩它们。最后让我们得到不同的country 和age 值:
const distinctAgesAndCountries = distinct(arr, "country", "age");
console.log(distinctAgesAndCountries);
/* [{ "country": "USA", "age": 35 }, { "country": "USA", "age": 40 },
{ "country": "Mexico", "age": 35 }] */
这是{country: string, age: number} 对象的数组。
无论如何,希望能给你一些方向。
Playground link to code