views:

67

answers:

5

Hi, can someone please help me turn this nested structure into a single LINQ statement?

        EventLog[] logs = EventLog.GetEventLogs();
        for (int i = 0; i < logs.Length; i++)
        {
            if (logs[i].LogDisplayName.Equals("AAA"))
            {
                for (int j = 0; j < logs[i].Entries.Count; j++)
                {
                    if (logs[i].Entries[j].Source.Equals("BBB"))
                    {
                        remoteAccessLogs.Add(logs[i].Entries[j]);
                    }
                }
            }
        }
A: 

Try this:

 EventLog[] logs = EventLog.GetEventLogs(); 
 remoteAccessLogs.AddRange(
   logs.Where(l => l.LogDisplayName.Equals("AAA"))
     .Select(l => l.Entries)
     .Where(le => le.Source.Equals("BBB"));

However if performance is an issue I would expect this has at least the same algorithmic complexity, if not worse, as we are iterating over the list again to AddRange.

Graphain
A: 

Try the following:

from log in logs 
where log.LogDisplayName.Equals("AAA")
select 
   (from entry in log.Entries
    where entry.Source.Equals("BBB")
    select entry);
Shirik
A cross join would be a simpler approach
Sir Psycho
A: 

I have this solution, and I'm assuming that remoteAccessLogs is of type List

remoteAccessLogs.AddRange(

        from log in EventLog.GetEventLogs()
        from entry in log.Entries.Cast<EventLogEntry>()
        select entry
    );

Edit

I forgot about the where clauses

List<EventLogEntry> remoteAccessLogs = new List<EventLogEntry>();


    remoteAccessLogs.AddRange(

        from log in EventLog.GetEventLogs()
        where log.LogDisplayName.Equals("AAA")
        from entry in log.Entries.Cast<EventLogEntry>()
        where entry.Source.Equals("BBB")
        select entry
    );
Sir Psycho
Uh, no, he meant nested, like it is.
Shirik
+3  A: 

Nested loops usually end up with multiple "from" clauses (which are converted into calls to SelectMany by the compiler):

var remoteAccessLogs = from log in EventLogs.GetEventLogs()
                       where log.LogDisplayName == "AAA"
                       from entry in log.Entries
                       where entry.Source == "BBB"
                       select entry;

(That's assuming that remoteAccessLogs is empty before this call, and that you're happy iterating over it directly - you can call ToList() if you want a List<T>.)

Here's the dot notation form:

var remoteAccessLogs = EventLogs.GetEventLogs()
                                .Where(log => log.LogDisplayName == "AAA")
                                .SelectMany(log => log.Entries)
                                .Where(entry => entry.Source == "BBB");

Or for a list:

var remoteAccessLogs = EventLogs.GetEventLogs()
                                .Where(log => log.LogDisplayName == "AAA")
                                .SelectMany(log => log.Entries)
                                .Where(entry => entry.Source == "BBB")
                                .ToList();

Note that I've used the overloaded == for string as I find it easier to read than calling the Equals method. Either will work though.

Jon Skeet
I always forget it's acceptable to use `==` as per http://msdn.microsoft.com/en-us/library/aa664728(VS.71).aspx
Graphain
I do wish that code samples displayed correctly on the iPhone. One for meta me thinks!
Jamie Dixon
A: 

Have a Look ...

List<Entries> result = new List<Entries>();
GetEventLogs().Where(x => x.LogDisplayName.Equals("AAA")).ToList().ForEach(delegate(Log en)
        {
            en.Entries.Where(y => y.Source.Equals("BBB", StringComparison.InvariantCultureIgnoreCase)).ToList().ForEach(delegate(Entries ent)
            {
                result.Add(ent);
            });
        });
Samdrain