简体   繁体   中英

c# - using SelectMany to merge multiple lists

As of right now, I use the following code to merge two List<string> lists and order them by a timestamp

var list = report[0];  
var list2 = report[1];
var result = list
    .Union(list2)
    .Select(x =>
    {  return new {Log = x, Time = TimeSpan.Parse(x.Split(' ')[0])}; })
    .OrderBy(x => x.Time)
    .ToList(); 

The issue now is that I have to handle more than two lists, up to n . I have looked into the SelectMany examples but it does not seem to be supporting the same functionality as Select does. Another way I was planning to do this was using foreach loop but it does not seem to be an efficient way, especially if the list get bigger.
Edit (added sample data and expected result):
An example list1 can look something like this:
11:03:01:003 INFO some event has occurred 11:03:31:004 DEBUG another event has occurred 11:04:01:015 INFO third event has occurred
An example list2 can look something like this:
11:03:16:003 INFO fourth event has occurred 11:03:32:025 DEBUG fifth event has occurred 11:03:54:023 INFO sixth event has occurred
And, therefore, there can multiple lists like that. An expected merge of these two lists will look the following way:
11:03:01:003 INFO some event has occurred 11:03:16:003 INFO fourth event has occurred 11:03:31:004 DEBUG another event has occurred 11:03:32:025 DEBUG fifth event has occurred 11:03:54:023 INFO sixth event has occurred 11:04:01:015 INFO third event has occurred

You can use SelectMany here:

// suppose reports is of type List<List<SomeClass>>
reports.SelectMany(x => x)
    .Select(x =>
        {  return new {Log = x, Time = TimeSpan.Parse(x.Split(' ')[0])}; })
    .OrderBy(x => x.Time)
    .ToList(); 

Adding a .Distinct call will make it have the same effect as Union :

reports.SelectMany(x => x).Distinct()
    .Select(x =>
        {  return new {Log = x, Time = TimeSpan.Parse(x.Split(' ')[0])}; })
    .OrderBy(x => x.Time)
    .ToList(); 

Alternatively, keep using Union :

IEnumerable<SomeClass> query = reports[0];
for (int i = 1 ; i < reports.Length ; i++) {
   query = query.Union(reports[i]);
}

I'm assuming report is an IEnumerable of IEnumerable<string> . So you need something like this:

report.SelectMany(l => l.Select(x => new {Log = x, Time = TimeSpan.Parse(x.Split(' ')[0])}))
    .OrderBy(x => x.Time)
    .ToList();

SelectMany will union all results of the l.Select , then you order them by time.

EDIT:

Since it was pointed out that Union removes duplicates, you need to add Distinct to get the same result:

report.SelectMany(l => l.Select(x => new {Log = x, Time = TimeSpan.Parse(x.Split(' ')[0])}))
    .Distinct()
    .OrderBy(x => x.Time)
    .ToList();

There are several solutions for this, one of them could be:

List<IEnumerable<string>> allLists = new List<IEnumerable<string>>();
            allLists.Add(report[0]);
            allLists.Add(report[1]);
            allLists.Add(report[2]);

            var result = allLists.SelectMany(l => l.Select(x => new
            {
                Log = x,
                Time = TimeSpan.Parse(x.Split(' ')[0])
            })).OrderBy(x => x.Time)
            .ToList();

Not sure why the other answers have extra .Select :

var result = report
       .SelectMany(l => l, (l, x) => new { Log = x, Time = TimeSpan.Parse(x.Split(' ')[0]) })
       .Distinct().OrderBy(x => x.Time).ToList(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM