#c# #asp.net #.net #arrays #linq
#c# #asp.net #.net #массивы #linq
Вопрос:
У меня есть следующий массив объекта TrackerReport:
public class TrackerReport : TrackerMilestone
{
public long Views { get; set; }
public override string ToString()
{
return "Id=" MilestoneId " | Name=" Name " | Views = " Views;
}
Я также публикую родительский класс, чтобы лучше объяснить:
public class TrackerMilestone
{
public int MilestoneId { get; set; }
public int CampaignId { get; set; }
public string Name { get; set; }
public int? SortIndex { get; set; }
public string Url { get; set; }
public bool IsGoal { get; set; }
public bool IsPartialGoal { get; set; }
public int? ParentMilestoneId { get; set; }
public int? ViewPercent { get; set; }
public override string ToString()
{
return "Id=" MilestoneId " | Name=" Name " | Url = " Url;
}
}
Чтобы оно отображалось так более или менее:
ID Name Url Counter
1 A ab.com 5
2 N ac.com 2
И у меня есть список этого объекта, который я заполняю таким образом:
var trackerReportList = new List<TrackerReport[]>();
foreach (var trackerItem in trackerChildren)
{
//currentReport is the array of TrackerReport TrackerReport[] above mentioned
var currentReport = GetReportForItem(GetFromDate(), GetToDate(), trackerItem.ID,
FindCampaignId(trackerItem));
trackerReportList.Add(currentReport);
}
Все записи имеют одинаковые значения, но счетчик, так что, например:
список 1:
ID Name Url Counter
1 A ab.com 5
2 N ac.com 2
список 2:
ID Name Url Counter
1 A ab.com 17
2 N ac.com 28
Моя цель — сгенерировать один TrackerReport[] с суммой значений счетчика в качестве счетчика.
TrackerReport[]:
ID Name Url Counter
1 A ab.com 22
2 N ac.com 30
Есть ли какой-либо запрос Linq для этого? Или, если вы придумаете лучшее решение, просто опубликуйте его.
Заранее спасибо!
Комментарии:
1. ну, трекер — это точно парень: P
Ответ №1:
Вот как это сделать с помощью Linq.
- Во-первых, вы хотите получить данные в одном списке, а не в
List
спискеArrays
. Мы можем сделать это сSelectMany
помощью .trackerReportList.SelectMany(c => c)
сглаживаетсяList<TrackerReport[]>()
вIEnumerable<TrackerReport>
- Затем вы группируете объекты по соответствующему столбцу / столбцам
group p by new { ID = p.MilestoneId, Name = p.Name, Url = p.Url} into g
- Наконец, вы проецируете группировку в нужный нам формат.
Counter
получаетсяAdding
Views
для коллекции объектов в каждой группе.select new { ... };
Собрать все это вместе:
var report = from p in trackerReportList.SelectMany(c => c)
group p by new {
ID = p.MilestoneId,
Name = p.Name,
Url = p.Url} into g
select new {
ID = g.Key.ID,
Name = g.Key.Name,
Url = g.Key.Url,
Counter = g.Sum(c => c.Views)
};
Комментарии:
1. Tnx много, я видел это решение после того, как уже попробовал другое
Ответ №2:
Это lambda expression
для вашего запроса.
TrackerReport[] trackerInfoList = trackerReportList
.SelectMany(s => s)
.GroupBy(g => g.MilestoneId)
.Select(s =>
{
var trackerReportCloned = Clone<TrackerReport[]>(s.First());
trackerReportCloned.Views = s.Sum(su => su.Views);
return trackerReportCloned;
})
.ToArray();
Если вы заметили, я использовал Clone<T>(T)
метод глубокого клонирования object
по сгруппированному значению. Я мог бы сделать это, скопировав каждое свойство, но я нашел это самым простым.
Это и есть Clone()
метод:
public static T Clone<T>(T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
Прежде чем продолжить, вам необходимо установить [Serializable]
атрибут для ваших DTO
объектов.
[Serializable]
public class TrackerReport : TrackerMilestone
{
.
.
.
}
[Serializable]
public class TrackerMilestone
{
.
.
.
}
Надеюсь, это то, что вы ищете.
Ответ №3:
Я бы сделал это следующим образом: 1) Пусть TrackerReports[] resultList
это массив глубоких копий trackerReportList[0]
элементов 2) Как я понимаю, свойство Views соответствует столбцу счетчика. Если это так, то
foreach(report in resultList)
{
report.Views = trackerReportList.Sum(reports => reports.Single(r => r.MilestoneId == report.MilestoneId).Views);
}