Typescript 如何检查排版脚本集数据结构中的列表相等性?

Typescript 如何检查排版脚本集数据结构中的列表相等性?,typescript,Typescript,考虑以下类型脚本代码 const s = new Set<number[]>() s.add([1, 2]) s.add([3, 4]) s.add([1, 2]) for (let t of s) { console.log(t) } // prints [1, 2], [3, 4], [1, 2], but i would like the set not to have the [1, 2] duplicate console.log(s.has([1, 2])) // p

考虑以下类型脚本代码

const s = new Set<number[]>()
s.add([1, 2])
s.add([3, 4])
s.add([1, 2])
for (let t of s) {
  console.log(t)
} // prints [1, 2], [3, 4], [1, 2], but i would like the set not to have the [1, 2] duplicate
console.log(s.has([1, 2])) // prints false, i don't why it return false but I would like to return true

如何重写Typescript代码,使set在Python代码中起作用?TIA

在python中,集合依赖于项上正确的散列和均衡实现,因此它可以同时

避免保存重复的值 检查值的成员资格 然而,在javascript中,Set的功能相对较少。项目成员资格大致基于===所做的任何事情,但需要注意的是,NaN被视为与NaN相同,有关详细信息,请参阅。这意味着对于对象和数组,它使用引用相等

因此,在您的示例中,如果我们希望获得类似于python示例的行为,那么我们需要像这样使用相同的引用

const s = new Set<number[]>();
const oneTwo = [1,2];
const threeFour = [3,4];
s.add(oneTwo);
s.add(threeFour);
s.add(oneTwo);
s、 由于JavaScript的工作方式,has[1,2]返回false

console.log[]=[]; 将返回false,因为它不是同一个对象

我首选的方法是创建扩展数组的CustomSet类,然后实现自己的.add和.has


我认为这是不可行的,因为相同的数组将指向不同的实例。如果您尝试以下方法:

class FooSet<P> {
  public s = new Set<P>();

  public has(foo: P): boolean {
    for (let item of this.s.values()) {
      // Hacky way to check equality between arrays
      // Do not do this
      if (JSON.stringify(item) === JSON.stringify(foo)) {
        return true;
      }
    }

    return false;
  }

  public add(foo: P) {
    let elementExists = this.has(foo);

    if (!elementExists) {
      this.s.add(foo);
    }
  }
}

const s = new FooSet<number[]>();

s.add([1, 2]);
s.add([2, 3]);
s.add([1, 2]);

for (let t of s.s) {
  console.log(t);
}

console.log(s.has([1, 2]));

您将看到集合的行为以及它如何声明唯一性。因此,为了支持您的用例,您需要构建一些包装集合的自定义函数

您已经收到了一些关于集合的解释

我喜欢纯类型

首先,TS不能很好地处理可变值。它只是不跟踪突变

第二,请记住,我的第一个例子在实践中并不是非常有用。我只是想给你们更多的概述TS是如何工作的

我的第二个示例非常有用,我相信您可以使用它,但是我在实践中从未扩展过任何内置类。我相信@T.J.Crowder可以给你一些建议

为了强制TS进行一些检查,我们应该为add逻辑创建简单的包装器

const add=set,value=>set.addvalue 让我们添加一些类型:

类型值=[number,number]; 为了允许TS跟踪我们的添加操作,让我们添加一些缓存

函数添加 设置:S,值:[……VAL]{ 返回set.addvalue } 每次调用add时,我都会更新{{uu缓存?:any}

{{uu缓存?:any}->{uu缓存?:[]}->{uu缓存?:[1,2]}->{uu缓存?:[1,2]|[3,4]}等

这是我们的主要逻辑:

类型UpdateProp= T扩展{uuu缓存?:any[]} ? 集合与局部 :T部分(&P) 类型检查=T扩展{uuuu缓存?:推断R}?值扩展R?1 : 2 : 3 函数添加< S扩展集|集&{uu缓存?:值}, VAL扩展值 >设置:S,值:[…VAL],…标志:检查扩展1?[从未]:[]:UpdateProp 我希望第一个参数总是一个没有缓存的集合,或者是一个有缓存的集合&{uuucache?:Value}

VAL扩展值推断两个数字的数组

UpdateProp smth类似于

const updateProp=obj,值=>{ 返回{ …obj, [''缓存']:值 } } …标志:是否选中扩展1?[从不]:[]-小验证技巧。你可以找到完整的解释 因此,每次smbd调用addset时,[2,3]\u缓存属性都将被更新/联合

请记住,缓存是可选的,所以不要担心,TS不会允许这样的smth:set.\u缓存

完整代码:

类型值=[数字,数字] 类型UpdateProp= T扩展{uuu缓存?:any[]} ? 集合与局部 :T部分(&P) 类型检查=T扩展{uuuu缓存?:推断R}?值扩展R?1 : 2 : 3 函数添加< S扩展集|集&{uu缓存?:值}, VAL扩展值 >设置:S,值:[…VAL],…标志:检查扩展1?[从未]:[]:UpdateProp 函数添加 设置:S,值:[……VAL]{ 返回set.addvalue } const result=addnew Set[1,2]//确定 const result2=addresult[3,4]//确定 const result3=addresult2[3,4]//预期错误 const result4=addresult2[4,3]//确定 如果你还想像所有人一样,以正常的方式使用Set

您可以扩展集合类:

类MySet扩展集{ 覆盖addval:T{ 常数[x,y]=val const keys=[…this.keys]; const exists=keys.findIndex[a,b]=>a==x&&b==y 如果存在==-1{ 还这个 } super.addval 还这个 } } 我使用了TS 4.3中新增的override关键字。如果您有较低版本的TS,请随意丢弃它

const areArraysEqual = (arrayA: number[], arrayB: number[]): boolean => {
    return arrayA.every((val, i) => val === arrayB[i]);
}

const insertIntoSet = (set: Array<number[]>, value: number[]): void => {
    const alreadyInSet = set.some((entry) => areArraysEqual(entry, value));
    if (!alreadyInSet) {
        set.push(value);
    }
}

class CustomSet extends Array<number[]> {
  add(arr: number[]) {
    if (!this.has(arr)) this.push(arr);
  }

  has(arr: number[]) {
    for (let i = 0; i < this.length; i++) {
      if (this[i].every((v, j) => v === arr[j])) return true;
    }       
    return false;
  }
}

const s = new CustomSet()
s.add([1, 2])
s.add([3, 4])
s.add([1, 2])

console.log(t); // [[1, 2], [3, 4]] 
console.log(s.has([1, 2])); // true
console.log(s.has([1, 3])); // false
class FooSet<P> {
  public s = new Set<P>();

  public has(foo: P): boolean {
    for (let item of this.s.values()) {
      // Hacky way to check equality between arrays
      // Do not do this
      if (JSON.stringify(item) === JSON.stringify(foo)) {
        return true;
      }
    }

    return false;
  }

  public add(foo: P) {
    let elementExists = this.has(foo);

    if (!elementExists) {
      this.s.add(foo);
    }
  }
}

const s = new FooSet<number[]>();

s.add([1, 2]);
s.add([2, 3]);
s.add([1, 2]);

for (let t of s.s) {
  console.log(t);
}

console.log(s.has([1, 2]));