用于检查数组中的重复项的通用 Typescript 函数

Posted

技术标签:

【中文标题】用于检查数组中的重复项的通用 Typescript 函数【英文标题】:Generic Typescript function to check for duplicates in an array 【发布时间】:2021-11-11 00:54:28 【问题描述】:

我正在尝试创建一个通用的 Typescript 函数来检查数组是否包含重复项。例如:

interface Student 
  name: string;
  class: string;
;

const students: Student[] = [
   name: 'John Smith', class: 'Science' ,
   name: 'Edward Ryan', class: 'Math' ,
   name: 'Jessica Li', class: 'Social Studies',
   name: 'John Smith', class: 'English'
];

那是数据。

这就是我想要对数据做的事情:

const registerStudents = async (students: Student[]): Promise<void> 
  
  checkDuplicate(students, existingState); //This is the function I want to build

  const response = await axios.post('/students/new', students)
  existingState.push(response); //pushes newly registers students to the existing state
;

关于checkDuplicate(),我想让它成为一个通用函数,但我在逻辑上遇到了困难。

export const checkDuplicate = <T>(items: T[], existingState: T[]): void 
  //checks if the items have any duplicate names, in this case, it would be 'John Smith', and if so, throw an error

  //Also checks if items have any duplicate names with the existingState of the application, and if so, throw an error

  if (duplicate) 
    throw new Error('contains identical information')
  ;
;

这有点复杂,我无法弄清楚使用 typescript 的逻辑。任何关于我如何实现这一点的建议都将不胜感激!

【问题讨论】:

this 是否满足您的需求?如果是这样,我可以写一个答案。如果没有,您能否解释一下您将如何在纯 javascript 中实现 checkDuplicate() 或者它是否不是通用的?然后我也许可以给它类型。 哇,这太完美了,我需要一些时间来理解这段代码,但它运行良好。 好的,我会在有机会的时候写一个带有解释的答案。 【参考方案1】:

解决此问题的一个合理方法是让checkDuplicate() 采用一个泛型类型T[] 的单个数组items,以及另一个K[] 类型的数组keysToCheck,其中K 是一个keylike 类型(或 union 的 keylike 类型),其中 T 是具有 K 中的键的类型,并且这些键的值是 strings。即checkDuplicate()的调用签名应该是

declare const checkDuplicate: <T extends Record<K, string>, K extends PropertyKey>(
    items: T[],
    keysToCheck: K[]
) => void;

这个函数应该遍历itemskeysToCheck,如果它发现一个项目的属性与前一个项目中的相同属性是相同的字符串,它应该抛出一个错误。

如果你有这样的功能,你可以编写接受studentsexistingState的版本,两个Student对象数组,像这样:

function checkDuplicateStudents(students: Student[], existingState: Student[]) 
    checkDuplicate([...students, ...existingState], ["name", "class"]);

我们在哪里 spreading 将 studentsexistingState 数组合并到一个数组中,作为 items 传递给 checkDuplicate(),因为我们正在检查 Student,所以我们将 ["name", "class"] 作为 @987654349 传递@。


这是checkDuplicate() 的可能实现:

const checkDuplicate = <T extends Record<K, string>, K extends PropertyKey>(
    items: T[],
    keysToCheck: K[]
): void => 
    const vals =  as Record<K, Set<string>>;
    keysToCheck.forEach(key => vals[key] = new Set());
    for (let item of items) 
        for (let key of keysToCheck) 
            const val: string = item[key];
            const valSet: Set<string> = vals[key]
            if (valSet.has(val)) 
                throw new Error(
                    'contains identical information at key "' +
                    key + '" with value "' + val + '"');
            ;
            valSet.add(val);
        
    

它的工作方式是我们创建一个名为vals 的对象,其中keysToCheck 的每个元素key 都有一个键。每个元素vals[key] 是我们已经看到的key 的字符串Set。每次我们在items 数组中的任何item 中看到string-valued 属性val 和键key,我们检查vals[key] 中的集合是否具有val。如果是这样,我们之前已经看到了这个键的这个值,所以我们抛出一个错误。如果没有,我们将其添加到集合中。

(请注意,可以将Set&lt;string&gt; 替换为Record&lt;string, true | undefined&gt; 形式的普通对象,如Mimicking sets in JavaScript? 所示,但为了清楚起见,我在这里使用Set。)


好的,让我们根据您的示例对其进行测试:

checkDuplicateStudents(students, []);
// contains identical information at key "name" with value "John Smith"

看起来不错。它在运行时抛出错误并正确识别重复数据。

Playground link to code

【讨论】:

很好的答案,感谢您花时间解释您的逻辑!

以上是关于用于检查数组中的重复项的通用 Typescript 函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 Perl 检查数据数组中重复项的最有效方法是啥?

检查一组集合中的重复项的更有效方法是啥

删除数组中的重复项,但添加一个计数属性以查看重复项的数量

删除排序数组中的重复项的golang实现

用于密码字母表的自定义数组shuffle中的重复项

计算数组中前面重复项的数量