#c# #list
#c# #Список
Вопрос:
Я пытаюсь выяснить, как извлекать объекты определенного типа из объекта списка, содержащего другие объекты списка, без необходимости перебирать все дерево объектов вручную.
Я знаю, что могу создать какой-то цикл и проверять каждый тип объектов, но мне нужен более эффективный и красивый способ сделать это, например, оператор LINQ или какое-то вложенное лямбда-выражение или любые другие предложения, которые у вас могут быть.
Итак, у меня есть объект класса, который имеет элемент списка, который также имеет элемент списка, который также имеет элемент списка, например:
- Тип расписания
- Список periodType
- Запись списка
- Рабочий день списка
- Запись списка
- Список periodType
И я хочу получить все объекты типа WorkDay.
Вот пример кода. Я создал пример объекта, содержащего 4 объекта WorkDay, расположенных в дереве. Как мне эффективно извлекать их?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
public class TimesheetType
{
public List<PeriodType> PeriodTypes { get; set; }
}
public class PeriodType
{
public List<Entry> Entrys { get; set; }
}
public class Entry
{
public List<WorkDay> WorkDays { get; set; }
}
public class WorkDay
{
public DateTime Date { get; set; }
public double Hours { get; set; }
}
class Program
{
static void Main(string[] args)
{
TimesheetType timesheetType = CreateTimesheetTypeExample();
// Get all WorkDay typed objects in the tree, should return a List<WorkDay> with 4 items in it
//var allWorkDays = timesheetType.PeriodTypes.Select(...)
}
private static TimesheetType CreateTimesheetTypeExample()
{
TimesheetType timesheetType = new TimesheetType
{
PeriodTypes = new List<PeriodType>()
{
{
new PeriodType()
},
{
new PeriodType()
},
{
new PeriodType()
},
}
};
timesheetType.PeriodTypes[0].Entrys = new List<Entry>()
{
{
new Entry()
}
};
timesheetType.PeriodTypes[1].Entrys = new List<Entry>()
{
{
new Entry()
}
};
timesheetType.PeriodTypes[2].Entrys = new List<Entry>()
{
{
new Entry()
}
};
timesheetType.PeriodTypes[0].Entrys[0].WorkDays = new List<WorkDay>(1)
{
new WorkDay() { Date = DateTime.Parse("2020-01-01"), Hours = 3 },
new WorkDay() { Date = DateTime.Parse("2020-01-02"), Hours = 6 }
};
timesheetType.PeriodTypes[2].Entrys[0].WorkDays = new List<WorkDay>(1)
{
new WorkDay() { Date = DateTime.Parse("2020-01-03"), Hours = 12 },
new WorkDay() { Date = DateTime.Parse("2020-01-04"), Hours = 24 }
};
return timesheetType;
}
}
}
Комментарии:
1. Использование linq не делает его более эффективным ни при каком воображении. Удобно? Конечно. Циклы все равно где-то происходят, где-то это Linq.
Ответ №1:
Предполагая PeriodTypes
, Entries
, WorkDays
(так что все списки) никогда не равны нулю (но могут быть пустыми), пара SelectMany
должна сделать трюк:
var allWorkDays = timesheetType.PeriodTypes
.SelectMany(c => c.Entrys)
.SelectMany(c => c.WorkDays).ToList();
SelectMany
выравнивает вложенный список, именно то, что вы хотите сделать.
В вашем примере, хотя списки могут быть нулевыми, вам нужно отфильтровать нули:
var allWorkDays = timesheetType.PeriodTypes.
Where(c => c.Entrys != null).SelectMany(c => c.Entrys)
.Where(c => c.WorkDays != null).SelectMany(c => c.WorkDays)
.ToList();
Или как это:
var allWorkDays = timesheetType.PeriodTypes
.SelectMany(c => c.Entrys ?? new List<Entry>())
.SelectMany(c => c.WorkDays ?? new List<WorkDay>())
.ToList();
Комментарии:
1. отлично! Именно то, что я искал!