如何使用打字稿制作笛卡尔产品?

发布于 2025-01-25 02:49:26 字数 2429 浏览 3 评论 0原文

这是我所追求的类型签名:

function cartesianProduct<T1, T2, T3, T4, T5, T6, T7, T8>([c1, c2, c3, c4, c5, c6, c7, c8]: [T1[], T2[], T3[], T4[], T5[], T6[], T7[], T8[]]): [T1, T2, T3, T4, T5, T6, T7, T8][];
function cartesianProduct<T1, T2, T3, T4, T5, T6, T7>([c1, c2, c3, c4, c5, c6, c7]: [T1[], T2[], T3[], T4[], T5[], T6[], T7[]]): [T1, T2, T3, T4, T5, T6, T7][];
function cartesianProduct<T1, T2, T3, T4, T5, T6>([c1, c2, c3, c4, c5, c6]: [T1[], T2[], T3[], T4[], T5[], T6[]]): [T1, T2, T3, T4, T5, T6][];
function cartesianProduct<T1, T2, T3, T4, T5>([c1, c2, c3, c4, c5]: [T1[], T2[], T3[], T4[], T5]): [T1, T2, T3, T4, T5][];
function cartesianProduct<T1, T2, T3, T4>([c1, c2, c3, c4]: [T1[], T2[], T3[], T4[]]): [T1, T2, T3, T4][];
function cartesianProduct<T1, T2, T3>([c1, c2, c3]: [T1[], T2[], T3[]]): [T1, T2, T3][];
function cartesianProduct<T1, T2>([c1, c2]: [T1[], T2[]]): [T1, T2][];
function cartesianProduct<T>(sets: T[][]): T[][] {
  // implementation
}

这是我希望它能做的示例。给定:

const input = [
  [ 'a', 'b' ],
  [ 1, 2 ],
];

它会吐出来:

const output = [
  [ 'a', 1 ],
  [ 'a', 2 ],
  [ 'b', 1 ],
  [ 'b', 2 ],
];

尝试使用此参考实现给我们这个类型的问题:

Here's a playground

Here's the type signature that I'm after:

function cartesianProduct<T1, T2, T3, T4, T5, T6, T7, T8>([c1, c2, c3, c4, c5, c6, c7, c8]: [T1[], T2[], T3[], T4[], T5[], T6[], T7[], T8[]]): [T1, T2, T3, T4, T5, T6, T7, T8][];
function cartesianProduct<T1, T2, T3, T4, T5, T6, T7>([c1, c2, c3, c4, c5, c6, c7]: [T1[], T2[], T3[], T4[], T5[], T6[], T7[]]): [T1, T2, T3, T4, T5, T6, T7][];
function cartesianProduct<T1, T2, T3, T4, T5, T6>([c1, c2, c3, c4, c5, c6]: [T1[], T2[], T3[], T4[], T5[], T6[]]): [T1, T2, T3, T4, T5, T6][];
function cartesianProduct<T1, T2, T3, T4, T5>([c1, c2, c3, c4, c5]: [T1[], T2[], T3[], T4[], T5]): [T1, T2, T3, T4, T5][];
function cartesianProduct<T1, T2, T3, T4>([c1, c2, c3, c4]: [T1[], T2[], T3[], T4[]]): [T1, T2, T3, T4][];
function cartesianProduct<T1, T2, T3>([c1, c2, c3]: [T1[], T2[], T3[]]): [T1, T2, T3][];
function cartesianProduct<T1, T2>([c1, c2]: [T1[], T2[]]): [T1, T2][];
function cartesianProduct<T>(sets: T[][]): T[][] {
  // implementation
}

Here's an example of what I expect it to do. Given:

const input = [
  [ 'a', 'b' ],
  [ 1, 2 ],
];

It would spit out:

const output = [
  [ 'a', 1 ],
  [ 'a', 2 ],
  [ 'b', 1 ],
  [ 'b', 2 ],
];

Trying to utilize this reference implementation gives us this type problem:

enter image description here

Here's a playground.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空‖城人不在 2025-02-01 02:49:26

如果您想使用ramda,则可以使用 r.SequeSection带有数组。

const cartesianProduct = R.sequence(Array.of)

const input = [
  [ 'a', 'b' ],
  [ 1, 2 ],
];

cartesianProduct(input)
//=> [["a", 1], ["a", 2], ["b", 1], ["b", 2]]

If you'd like to use Ramda, you can use R.sequence with arrays.

const cartesianProduct = R.sequence(Array.of)

const input = [
  [ 'a', 'b' ],
  [ 1, 2 ],
];

cartesianProduct(input)
//=> [["a", 1], ["a", 2], ["b", 1], ["b", 2]]
知足的幸福 2025-02-01 02:49:26

对于此类问题,我一直喜欢首先从类型开始。

首先是提取数组的元素类型的类型:

type ElementType<A> = A extends ReadonlyArray<infer T> ? T : never;

是的,我知道a [number]存在,但这将在以后导致类型错误,因为a将是结果从推断

然后,一种列出数组列表并为我们提供其元素类型的类型。

type ElementsOfAll<Inputs, R extends ReadonlyArray<unknown> = []> = Inputs extends readonly [infer F, ...infer M] ? ElementsOfAll<M, [...R, ElementType<F>]> : R;

它几乎就像inputs.map((f)=&gt; elementType(f))在代码中。

最后,我们使用这种类型来定义cartesianproduct类型:

type CartesianProduct<Inputs> = ElementsOfAll<Inputs>[];

现在我们以类型进行了代码进行此操作:

function cartesianProduct(sets) {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
}

这种惊人的实现是从这个出色的答案如果您的环境不支持flatflatmap,则可以在哪里找到其他替代方案。

在实现此实现之后,我们添加了类型:

function cartesianProduct<Sets extends ReadonlyArray<ReadonlyArray<unknown>>>(sets: Sets): CartesianProduct<Sets> {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
}

但是存在错误,因为返回类型与redair调用的类型不匹配。 Unfortunately I don't know a good way to rid the error but if a cast is acceptable:

function cartesianProduct<Sets extends ReadonlyArray<ReadonlyArray<unknown>>>(sets: Sets): CartesianProduct<Sets> {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat()))) as CartesianProduct<Sets>;
}

Playground

For problems like these I always like to start with the types first.

First a type to extract the element type of an array:

type ElementType<A> = A extends ReadonlyArray<infer T> ? T : never;

Yes, I know A[number] exists but this will result in type errors later on because A will be a result from infer.

Then a type that takes a list of arrays and gives us their element types.

type ElementsOfAll<Inputs, R extends ReadonlyArray<unknown> = []> = Inputs extends readonly [infer F, ...infer M] ? ElementsOfAll<M, [...R, ElementType<F>]> : R;

It's almost like Inputs.map((F) => ElementType(F)) in code.

Finally we use this type to define a CartesianProduct type:

type CartesianProduct<Inputs> = ElementsOfAll<Inputs>[];

Now that we did it in types it's time to do it in code:

function cartesianProduct(sets) {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
}

This amazing implementation was taken from this excellent answer where you can find other alternatives if your environment does not support flat or flatMap.

After we have this implementation we add the types:

function cartesianProduct<Sets extends ReadonlyArray<ReadonlyArray<unknown>>>(sets: Sets): CartesianProduct<Sets> {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
}

But there is an error because the return type does not match the type of the reduce call. Unfortunately I don't know a good way to rid the error but if a cast is acceptable:

function cartesianProduct<Sets extends ReadonlyArray<ReadonlyArray<unknown>>>(sets: Sets): CartesianProduct<Sets> {
  return sets.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat()))) as CartesianProduct<Sets>;
}

Playground

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文