#javascript #c# #arrays #typescript
#javascript #c# #массивы #typescript
Вопрос:
У меня есть список проектов, и каждый проект содержит список статусов. Мне нужно найти статус с определенным идентификатором во всех проектах.
В 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 с меньшим количеством кода?
Комментарии:
1. Эквивалентом было бы
this.selectedProjects.flatMap(x => x.status).find(f => f.Id == statusId)
. Но это собирает всеstatus
, а затем используетfind
. В вашем цикле вы замыкаете короткое замыкание, когда статус найден. Итак, ваш текущий код, вероятно, лучше по производительности2. Большое спасибо. Да, производительность — это тот момент, который следует учитывать. Но поскольку мои списки очень малы, это не должно быть проблемой при использовании flatMap.
Ответ №1:
Вы могли бы использовать flatMap, как предложил @adiga:
// >=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);
Комментарии:
1.
v.status
является массивом