【问题标题】:C# SelectMany alternative in Typescript / JavascriptTypescript / Javascript 中的 C# SelectMany 替代方案
【发布时间】:2021-04-16 09:12:18
【问题描述】:

我有一个项目列表,每个项目都包含一个状态列表。我需要在所有项目中找到具有特定 id 的状态。

在 C# 中我可以这样做:

List<StatusResponse> statusList = projects.SelectMany(x => x.Status).ToList();
StatusResponse status = statusList.Find(f => f.Id == id);

我什至可以在一行中完成所有操作:

StatusResponse status = projects.SelectMany(x => x.Status).FirstOrDefault(f => f.Id == id);

在 Typescript 中我这样做:

private getStatus(statusId: string): StatusResponse {

    for (let project of this.selectedProjects) {

        let status = project.status.find(find => find.id === statusId);
        if (status)
            return status;
    }

    return null;
}

问题:

Typescript 中是否有更简单的代码更少的解决方案?

【问题讨论】:

  • 相当于this.selectedProjects.flatMap(x =&gt; x.status).find(f =&gt; f.Id == statusId)。但这会收集所有status,然后使用find。在您的循环中,当找到状态时您会短路。因此,您当前的代码可能更适合性能
  • 非常感谢。是的,性能是需要考虑的一点。但是由于我的列表非常小,所以使用 flatMap 应该不是问题。

标签: javascript c# arrays typescript


【解决方案1】:

您可以按照@adiga 的建议使用flatMap

// >=ES2019
const status = this.selectedProjects.flatMap(pr => pr.status)
                                    .find(stat => stat.id === statusId);

或者,如果您的版本支持迭代器,您可以像这样创建一个可重用的泛型函数:

function* selectMany<TIn, TOut>(
    source: Iterable<TIn>,
    selector: (item: TIn) => Iterable<TOut>)
: Iterable<TOut> {
    for (const item of source) {
        const subItems = selector(item);
        for (const subItem of subItems) {
            yield subItem;
        }
    }
}

// and while we are at it. Let's make a FirstOrDefault equivalent.

function firstOrNull<T>(source: Iterable<T>, predicate: (item: T) => boolean): T | null {
    for (const item of source) {
        if (predicate(item)) {
            return item;
        }
    }
    return null;
}

示例用法:

interface Item {
    elements: Array<number>;
}

const items: Item[] = [
    {
        elements: [1, 2, 3]
    },
    {
        elements: [4, 5, 6]
    }
]

const elements = selectMany(items, itm => itm.elements);
for (const el of elements) {
    console.log(el);
}

输出:

1
2
3
4
5
6

firstOrNull(elements, itm => itm === 6); // 6
firstOrNull(elements, itm => itm === 7); // null

【讨论】:

    【解决方案2】:

    类似

    obj.map((v) => v.status).filter((v) => v.id === id);
    

    应该为您的应用程序运行四个,因为我猜您希望返回您的状态对象。否则,如果您想使用整个对象,您可以这样做:

    obj.filter((v) => v.status.id === id);
    

    如果你想要单个对象,你可以这样做,即

    obj.map((v) => v.status).find((status) => status.id === id);
    

    【讨论】:

    • v.status 是一个数组
    猜你喜欢
    • 2018-03-13
    • 2020-12-27
    • 2017-04-05
    • 2014-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 1970-01-01
    相关资源
    最近更新 更多