How to Use LINQ TakeWhile

Today I will talk about a simple and useful LINQ method called "TakeWhile". Enumerable.TakeWhile as defined on MSDN is a method that returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements. To show an example use of it, I provided a sample code that retrieve all numbers from a list that are less than 10 until it encounters a number greater or equal to 10.

int[] intnum = { 1, 3, 5, 7, 9, 11, 8, 9, 1, 2 };

var lessthan10 = intnum.TakeWhile(x => x < 10);

Console.WriteLine("Numbers that are less than 10.");
foreach (var x in lessthan10)
{
    Console.WriteLine(x);
}

The LINQ code above will produce the following result:

1
3
5
7
9

You can also apply it on a string list, as shown below.

string[] employees = { "auric", "rizza", "jayson", "fryan", "james", "cheesy" };

IEnumerable query =
    employees.TakeWhile(employee => String.Compare("fryan", employee, true) != 0);

foreach (string employee in query)
    Console.WriteLine(employee);

The LINQ code above will produce the following result:

auric
rizza
jayson

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Using IEqualityComparer and Lambda Expressions

Anyone using LINQ to manipulate in-memory collections is probably
also using plenty of lambda expressions to make things quite easy.
These two additions were really meant for each other. One of our
interns here recently ran into an interesting problem while using LINQ.
As a relatively new user of .NET based languages, reference types
caused him a bit of trouble.

The problem

While using the dot notation with lambda expressions, he was using the Except method in the following way.

List<MyObject> x = myCollection.Except(otherCollection).ToList();

Well the problem here is that these two collections contain
"MyObject"s, and when it does the comparison it does so based on the
reference. This means if those are separate but equivalent objects that
the comparison will claim they are different.

He had unit tests making sure that the except statement worked, but was using the same instance of variables to Assert, so the tests claimed to work.

I told him the problem and mentioned that there was probably an
overload of Except that allows one to specify how to do the comparison.
I was correct, but the overload takes an IEqualityComparer object. I
was hoping for a Func<x,x,bool> as the second parameter, so I did
what I always do; I Googled to see if anyone knew an easy way to get
that to work without doing extra work.

The Internet was kind enough to inform me that there was no built in way of handling this situation.

Building your own was the suggestion. It is a pretty simple class,
so it can just be tossed somewhere to be reused easily. It could easily
come up and be needed again.

public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _lambdaComparer;
private readonly Func<T, T, bool> _lambdaHash;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => o.GetHashCode())
{
}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
_lambdaComparer = lambdaComparer;
_lambdaHash = lambdaHash;
}
public bool Equals(T x, T y)
{
return _lambdaComparer(x, y);
}
public int GetHashCode(T obj)
{
return _lambdaHash(obj);
}
}

Now that we have a nice, Generic, comparer which can take lambda
expressions, we are all set to plug this in to the previous code.

List<MyObject> x = myCollection.Except(otherCollection,
new LambdaComparer<MyObject>((x, y) => x.Id == y.Id)).ToList();
// or
IEqualityComparer comparer = new LambdaComparer<MyObject>((x, y) => x.Id == y.Id);
List<MyObject> x = myCollection.Except(otherCollection, comparer).ToList();

I admit I am still kind of annoyed that there wasn't an overload which just took a Func<T, T, bool> or a Func<T, T, int>.

An alternative is to use this extension method so you can hide away the fact that you're using the custom comparer class.

public static class Ext
{
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second , Func<TSource, TSource, bool> comparer )
{
return first.Except(second, new LambdaComparer<TSource>(comparer));
}
}

 

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Get a List of Files and Folders Without Directory.GetFiles Access Denied Error

I know the title is a bit long, but it descriptive of the problem.
Recently I had need to retrieve a listing of files and folders given a
root path. All worked well, until I tested on Vista and Windows 7
machines. When trying to browse the "Users" folder, I kept getting
access denied errors and no lists returned. The problem is that
Directory.GetFiles and Directory.GetDirectories will fail on the first
sign of an access denied issue. On Vista and Windows 7, most of the
directories under the Users folder are ACL'd to not allow reading or
browsing.

The solution is to use a DirectoryInfo object to get the list of
directories, and loop through those. The solution I present below uses
PLINQ (Parallel LINQ) for multi-threaded looping. If you do not have
PLINQ installed, simply change the Parallel.ForEach statements to the
standard ForEach.

Notice the use of a Predicate in both functions. This allows you to
add advanced filtering, for example only returning files with an
extension of ".jpg", or only returning files modified in the last five
days.

 

using System;

using System.IO;

using System.Threading;


 

namespace MStaller


{


    internal static class DirectoryListing


    {

        #region DirectoryList


 


        /// <summary>


        /// Returns a list of directories under RootDirectory


        /// </summary>


        /// <param name="RootDirectory">starting directory</param>


        /// <param name="SearchAllDirectories">when true, all sub directories will be searched as well</param>


        /// <param name="Filter">filter to be done on directory. use null for no filtering</param>


        public static List<string> DirectoryList(string RootDirectory, bool SearchAllDirectories, Predicate<string> Filter)


        {


            List<string> retList = new List<string>();


 


            try


            {


                // create a directory info object


                DirectoryInfo di = new DirectoryInfo(RootDirectory);


 


                // loop through directories populating the list


                Parallel.ForEach(di.GetDirectories(), folder =>


                {


                    try


                    {


                        // add the folder if it passes the filter


                        if ((Filter == null) || (Filter(folder.FullName)))


                        {


                            // add the folder


                            retList.Add(folder.FullName);


 


                            // get it's sub folders


                            if (SearchAllDirectories)


                                retList.AddRange(DirectoryList(folder.FullName, true, Filter));


                        }


                    }


 


                    catch (UnauthorizedAccessException)


                    {


                        // don't really need to do anything


                        // user just doesn't have access


                    }


 


                    catch (Exception excep)


                    {


                        // TODO: log the exception


                    }


                });


            }


 


            catch (Exception excep)


            {


                // TODO: save exception


            }


 


            // return the list


            return retList;


        }


 


        // DirectoryList

        #endregion


 

        #region FileList


 


        /// <summary>


        /// Returns a list of files under RootDirectory


        /// </summary>


        /// <param name="RootDirectory">starting directory</param>


        /// <param name="SearchAllDirectories">when true, all sub directories will be searched as well</param>


        /// <param name="Filter">filter to be done on files/directory. use null for no filtering</param>


        public static List<string> FileList(string RootDirectory, bool SearchAllDirectories, Predicate<string> Filter)


        {


            List<string> retList = new List<string>();


 


            try


            {


                // get the list of directories


                List<string> DirList = new List<string> { RootDirectory };


 


                // get sub directories if allowed


                if (SearchAllDirectories)


                    DirList.AddRange(DirectoryList(RootDirectory, true, null));


 


                // loop through directories populating the list


                Parallel.ForEach(DirList, folder =>


                {


                    // get a directory object


                    DirectoryInfo di = new DirectoryInfo(folder);


 


                    try


                    {


                        // loop through the files in this directory


                        foreach (FileInfo file in di.GetFiles())


                        {


                            try


                            {


                                // add the file if it passes the filter


                                if ((Filter == null) || (Filter(file.FullName)))


                                    retList.Add(file.FullName);


                            }


 


                            catch (Exception excep)


                            {


                                // TODO: log the exception


                            }


                        }


                    }


 


                    catch (UnauthorizedAccessException)


                    {


                        // don't really need to do anything


                        // user just doesn't have access


                    }


 


                    catch (Exception excep)


                    {


                        // TODO: log the exception


                    }


                });


            }


 


            catch (Exception excep)


            {


                // TODO: save exception


            }


 


            // return the list


            return retList;


        }


 


        // FileList

        #endregion


    }

}

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Create T-SQL CASE Statements With LINQ To SQL

I was recently asked to help
with a LINQ To SQL query where the resulting T-SQL query was to
have CASE statements. Having CASE statements in T-SQL queries is a
common scenario but how do we it in LINQ To SQL? The solution is simple and straight-forward. As you will see below, using C#'s "Immediate If" will convert into T-SQL CASE statements.

I have created a table called CityWeather. This table has  two
fields: Name and Temperature. Here is the script if you wish to create
the table on your machine.

CREATE TABLE [dbo].[CityWeather](
[Name] [nvarchar](100) NOT NULL,
[Temperature] [decimal](18, 0) NOT NULL
) ON [PRIMARY]

 

My objective is to get LINQ To SQL to produce a T-SQL statement similar to this.

SELECT
Name,
Temperature,
CASE Temperature
WHEN 30 THEN 'Toasted'
WHEN 25 THEN 'I like it'
WHEN 10 THEN 'Just perfect'
WHEN -15 THEN 'Gonna freeze my'
END AS 'Message'
FROM CityWeather

Below is the C# code I wrote for my LINQ To SQL query.

from c in CityWeathers
select new
        {
          c.Name,
          c.Temperature,
          Messaage = c.Temperature == 30 ? "Toasted" : 
          c.Temperature == 25 ? "I like it" :
          c.Temperature == 10 ? "Just perfect" :
          c.Temperature == -15 ? "Gonna freeze my" : ""
        }

 

My LINQ To SQL query produced the following T-SQL Query

SELECT [t0].[Name], [t0].[Temperature],
(CASE
WHEN [t0].[Temperature] = @p0 THEN CONVERT(NVarChar(15),@p1)
WHEN [t0].[Temperature] = @p2 THEN CONVERT(NVarChar(15),@p3)
WHEN [t0].[Temperature] = @p4 THEN CONVERT(NVarChar(15),@p5)
WHEN [t0].[Temperature] = @p6 THEN @p7
ELSE CONVERT(NVarChar(15),@p8)
END) AS [Messaage]
FROM [CityWeather] AS [t0]
-- @p0: Input Decimal (Size = 0; Prec = 33; Scale = 4) [30]
-- @p1: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [Toasted]
-- @p2: Input Decimal (Size = 0; Prec = 33; Scale = 4) [25]
-- @p3: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [I like it]
-- @p4: Input Decimal (Size = 0; Prec = 33; Scale = 4) [10]
-- @p5: Input NVarChar (Size = 12; Prec = 0; Scale = 0) [Just perfect]
-- @p6: Input Decimal (Size = 0; Prec = 33; Scale = 4) [-15]
-- @p7: Input NVarChar (Size = 15; Prec = 0; Scale = 0) [Gonna freeze my]
-- @p8: Input NVarChar (Size = 0; Prec = 0; Scale = 0) []
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

LINQ to SQL changes in .NET 4.0

Well, it's official – LINQ to SQL is NOT dead in .NET 4.0. I'll say it again – LINQ to SQL is not dead.

Damian G, a developer at Microsoft working on LINQ to SQL for .NET 4.0, recently made a list of changes that will be coming out in the next release of .NET.

Change list

Performance

  • Query plans are reused more often by specifically defining text parameter lengths
  • Identity cache lookups for primary key with single result now
    includes
    query.Where(predicate).Single/SingleOrDefault/First/FirstOrDefault
  • Reduced query execution overhead when DataLoadOptions specified
    (cache lookup considers DataLoadOptions value equivalency – post beta
    1)

Usability

  • ITable<T> interface for additional mocking possibilities
  • Contains with enums automatically casts to int or string depending on column type
  • Associations can now specify non-primary-key columns on the other end of the association for updates
  • Support list initialization syntax for queries
  • LinqDataSource now supports inherited entities
  • LinqDataSource support for Dynamic Data query extenders added

Query stability

  • Contains now detects self-referencing IQueryable and doesn't cause a stack overflow
  • Skip(0) no longer prevents eager loading
  • GetCommand operates within SQL Compact transactions
  • Exposing Link<T> on a property/field is detected and reported correctly
  • Compiled queries now correctly detect a change in mapping source and throw
  • String.StartsWith, EndsWith and Contains now correctly handles ~ in the search string
  • Now detects multiple active result sets (MARS) better
  • Associations are properly created between entities when using eager loading with Table-Valued Functions (TVFs)
  • Queries that contain sub-queries with scalar projections now work better

Update stability

  • SubmitChanges no longer silently consumes transaction rollback exceptions
  • SubmitChanges deals with timestamps in a change conflict scenario properly
  • IsDbGenerated now honors renamed properties that don't match underlying column name
  • Server-generated columns and SQL replication/triggers now work instead of throwing SQL exception

General stability

  • Binary types equate correctly after deserialization
  • EntitySet.ListChanged fired when adding items to an unloaded entity set
  • Dispose our connections upon context disposal (ones passed in are untouched)

SQL Metal

  • Foreign key property setter now checks all affected associations not just the first
  • Improved error handling when primary key type not supported
  • Now skips stored procedures containing table-valued parameters instead of aborting process
  • Can now be used against connections that use AttachDbFilename syntax
  • No longer crashes when unexpected data types are encountered

LINQ to SQL class designer

  • Now handles a single anonymously named column in SQL result set
  • Improved error message for associations to nullable unique columns
  • No longer fails when using clauses are added to the partial user class
  • VarChar(1) now correctly maps to string and not char
  • Decimal precision and scale are now emitted correctly in the DbType attributes for stored procedures
  • Foreign key changes will be picked up when bringing tables back into the designer without a restart

Code generation (SQL Metal + LINQ to SQL class designer)

  • Stored procedures using original values now compiles when the entity and context namespaces differ
  • Virtual internal now generates correct syntax
  • Mapping attributes are now fully qualified to prevent conflicts with user types
  • KnownTypeAttributes are now emitted for DataContractSerializer with inheritance
  • Delay-loaded foreign keys now have the correct, compilable, code generated
  • Using stored procedures with concurrency no longer gets confused if entities in different namespace to context
  • ForeignKeyReferenceAlreadyHasValueException is now thrown if any association is loaded not just the first

Potentially breaking changes

We worked very hard to avoid breaking changes but of course any
potential bug fix is a breaking change if your application was
depending on the wrong behavior. The ones I specifically want to call
out are:

Skip(0) is no longer a no-op

The special-casing of 0 for Skip to be a no-op was causing some
subtle issues such as eager loading to fail and we took the decision to
stop special casing this. This means if you had syntax that was invalid
for a Skip greater than 0 it will now also be invalid for skip with a
0. This makes more sense and means your app would break on the first
page now instead of subtlety breaking on the second page. Fail fast :)

ForeignKeyReferenceAlreadyHasValue exception

If you are getting this exception where you weren’t previously it
means you have an underlying foreign key with multiple associations
based on it and you are trying to change the underlying foreign key
even though we have associations loaded.Best thing to do here is to set
the associations themselves and if you can’t do that make sure they
aren’t loaded when you want to set the foreign key to avoid
inconsistencies.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Use LINQ to Get a Count of Duplicates in a List

Often we have to get a count of duplicate items in a list. An easy way to do this is to group the list on the property we want to count, then use LINQ's GroupBy's Count feature. Below is a quick example using an employee list.

 

private static void Main()
{
    List<Employee> empList = new List<Employee>();

    empList.Add(new Employee() { ID = 1, FName = "John", Age=23, Sex='M'  });
    empList.Add(new Employee() { ID = 2, FName = "Mary", Age = 25, Sex = 'F' });
    empList.Add(new Employee() { ID = 3, FName = "Amber", Age = 23, Sex = 'M' });
    empList.Add(new Employee() { ID = 4, FName = "Kathy", Age=25, Sex='M'});
    empList.Add(new Employee() { ID = 5, FName = "Lena", Age=27, Sex='F'});
    empList.Add(new Employee() { ID = 6, FName = "John", Age = 28, Sex = 'M' });
    empList.Add(new Employee() { ID = 7, FName = "Kathy", Age = 27, Sex = 'F' });
    empList.Add(new Employee() { ID = 8, FName = "John", Age = 28, Sex = 'M' });

    var dup = empList
        .GroupBy(x => new { x.FName })
        .Select(group => new { Name = group.Key, Count = group.Count() })
        .OrderByDescending(x => x.Count);

    foreach (var x in dup)
    {
        Response.Write(x.Count + " " + x.Name);
    }
}

class Employee
{
    public int ID { get; set; }
    public string FName { get; set; }
    public int Age { get; set; }
    public char Sex { get; set; }
}

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Using LINQ to SQL with SQL Server Compact

In this
article, I will cover how to access data in SQL Server Compact
databases (.sdf file) using new development technologies such as LINQ.
LINQ is the new initiative of Microsoft to support Object-Relational
Mapping concepts and design patterns. LINQ provides a full type-safety
and compile-time checking of query expressions in order to minimize the
object-relational concepts mismatch and enables managing relational
data as objects providing an easy way to integrate data validation and
business logic rules into your application.

Getting started with the solution

The first step is open Visual Studio.NET 2008, and create a Console project (see Figure 1).

SQLServer1 Using LINQ to SQL with SQL Server Compact


Figure 1

Then
go to the installation of SQL Server Compact Edition in
$PROGRAMFILES$\Microsoft SQL Compact Edition\v3.5\Samples and copy the
Northwind.sdf file into the solution directory. Let's open a Command
Windows console and change to the solution directory.

Let's call
the SQLMetal.exe command in the Program Files\Microsoft
SDKs\Windows\v6.0A\Bin\ directory in order to generate the code and
mapping for the LINQ to SQL component of the .NET framework (see Figure
2).

SQLServer2 Using LINQ to SQL with SQL Server Compact


Figure 2

Now let's add the Northwind.cs file to the solution and a reference to the System.Data.Linq.dll assembly (see Figure 3).

SQLServer3 Using LINQ to SQL with SQL Server Compact


Figure 3

And finally, the sample code is shown in Listing 1.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LINQ_SQLCompact
{
    class Program
    {
        static void Main(string[] args)
        {
            string strConnString = "Northwind.sdf";
            Northwind dbNorthwind = new Northwind(strConnString);
 
            var query = from c in dbNorthwind.Customers
                        where c.City == "Paris"
                        select c;
 
            foreach (Customers c in query)
            {
                System.Console.WriteLine("ContactName={0}, Address={1}, City={2}",c.ContactName, c.Address, c.City);
            }
 
            System.Console.WriteLine("Press any key to finish …");
            System.Console.Read();

       }

    }

}

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

Returning a Single Element With LINQ First and LINQ Single

Sometimes you have a list, and you need to return a single element from the list. There are several ways to get the element to return. Below are two ways using LINQ with Lambda expressions.

Consider the following class:

   1: public class Person
   2: {
   3:     public string Name { get; set; }
   4:     public int Age { get; set; }
   5:     public bool Leader { get; set; }
   6: }

And let's load up some sample data:

   1: Person[] people = new Person[] {
   2:     new Person { Name = "Blue", Age = 25, Leader = true },
   3:     new Person { Name = "Gold", Age = 16, Leader = false },
   4:     new Person { Name = "Red", Age = 27, Leader = false },
   5:     new Person { Name = "Green", Age = 14, Leader = false}
   6: };

Now what we could do to find the leader (the assumption is that there is always only one leader):

   1: Person leader = people.Where(p => p.Leader == true).ToArray()[0];

The result of the people.Where() is an IEnumerable<Person>. 
And you can't just index the first element of that – so you convert it
to an array and index that instead.

LINQ provides two methods to perform this type of query without the
need of having an intermediate array — "First" and "Single":

   1: Person leader2 = people.First(p => p.Leader == true);
   2: Person leader3 = people.Single(p => p.Leader == true);

The difference between the two is that First grabs the first item it
finds.  The Single method expects only a single matching item and will
throw an exception if it finds more than one.  In this case, there is
only one Person in the array that has Leader set to true so both of
these lines of code produce the same result.

However, in the situation below:

   1: Person firstChild1 = people.First(p => p.Age < 18);
   2: Person firstChild2 = people.Single(p => p.Age < 18);

The first line will succeed.  The second line will fail since there are two people that are under 18.

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

GroupBy Multiple Values in LINQ

Here's a simple example to show you how to GroupBy Multiple Values
using LINQ. In this example, I am grouping by Age and Sex to find the
count of people who have the same age and sex.

C#

public partial class LINQ : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

      List<Employee> empList = new List<Employee>();

      empList.Add(new Employee() { ID = 1, FName = "John", Age=23, Sex='M'  });

      empList.Add(new Employee() { ID = 2, FName = "Mary", Age = 25, Sex = 'F' });

      empList.Add(new Employee() { ID = 3, FName = "Amber", Age = 23, Sex = 'M' });

      empList.Add(new Employee() { ID = 4, FName = "Kathy", Age=25, Sex='M'});

      empList.Add(new Employee() { ID = 5, FName = "Lena", Age=27, Sex='F'});

      empList.Add(new Employee() { ID = 6, FName = "Bill", Age = 28, Sex = 'M' });

      empList.Add(new Employee() { ID = 7, FName = "Celina", Age = 27, Sex = 'F' });

      empList.Add(new Employee() { ID = 8, FName = "John", Age = 28, Sex = 'M' });

 

      var sums = empList

               .GroupBy(x => new { x.Age, x.Sex })

               .Select(group => new { Peo = group.Key, Count = group.Count() });

 

      foreach (var employee in sums)
          Response.Write(employee.Count + ": " + employee.Peo);

    }

    class Employee

    {

        public int ID { get; set; }

        public string FName { get; set; }

        public int Age { get; set; }

        public char Sex { get; set; }

    }

VB.NET

Partial Public Class LINQ

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)

        Dim empList As New List(Of Employee)()

        empList.Add(New Employee() With {.ID = 1, .FName = "John", .Age = 23, .Sex = "M"c})

        empList.Add(New Employee() With {.ID = 2, .FName = "Mary", .Age = 25, .Sex = "F"c})

        empList.Add(New Employee() With {.ID = 3, .FName = "Amber", .Age = 23, .Sex = "M"c})

        empList.Add(New Employee() With {.ID = 4, .FName = "Kathy", .Age = 25, .Sex = "M"c})

        empList.Add(New Employee() With {.ID = 5, .FName = "Lena", .Age = 27, .Sex = "F"c})

        empList.Add(New Employee() With {.ID = 6, .FName = "Bill", .Age = 28, .Sex = "M"c})

        empList.Add(New Employee() With {.ID = 7, .FName = "Celina", .Age = 27, .Sex = "F"c})

        empList.Add(New Employee() With {.ID = 8, .FName = "John", .Age = 28, .Sex = "M"c})

        Dim sums = empList.GroupBy(Function(x) New With {Key x.Age, Key x.Sex}).Select(Function(group) New With {Key .Peo = group.Key, Key .Count = group.Count()})

        For Each employee In sums

            ' use employee.Count and employee.Key

        Next employee

    End Sub

 

    Public Class Employee

        Private privateID As Integer

        Public Property ID() As Integer

            Get

                Return privateID

            End Get

            Set(ByVal value As Integer)

                privateID = value

            End Set

        End Property

        Private privateFName As String

        Public Property FName() As String

            Get

                Return privateFName

            End Get

            Set(ByVal value As String)

                privateFName = value

            End Set

        End Property

 

        Private privateAge As Integer

        Public Property Age() As Integer

            Get

                Return privateAge

            End Get

            Set(ByVal value As Integer)

                privateAge = value

            End Set

        End Property

 

        Private privateSex As Char

        Public Property Sex() As Char

            Get

                Return privateSex

            End Get

            Set(ByVal value As Char)

                privateSex = value

            End Set

        End Property

    End Class

End Class

 

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark

How to Use LINQ GroupBy

The
GroupBy’ feature in LINQ is amazing and very powerful. When you use a
GroupBy’ in LINQ, internally it calls an extension method which
returns a sequence of System.Collections.Generic.IEnumerable<(Of
<(IGrouping<(Of <(TKey, TSource>)>)>)>)
The
GroupBy<(Of <(TSource, TKey>)>)(IEnumerable<(Of
<(TSource>)>), Func<(Of <(TSource, TKey>)>))
method returns a collection of IGrouping<(Of <(TKey,
TElement>)>) objects, one for each distinct key that was
encountered. The key represents the attribute that is common to each
value in the IGrouping<(Of <(TKey, TElement>)>) and can be
accessed using a ForEach loop.
In
order to understand GroupBy in LINQ, let’s take an example. Linda is an
HR in a small private firm. To facilitate the HR process, she wants a
simple console application to obtain some quick results. She needs the
following details of Employees:
-      Raw List of Employees
-      List of Employees grouped by the first letter of their FirstName
-      List of employees grouped by the Year in which they were born
-      List of employees grouped by the Year and Month in which they were born
-      Total count of employees having Birthdays in the same Year
-      Sex Ratio
Let’s
take these requirements one by one and see how they can be easily
achieved using the ‘GroupBy’ in LINQ. We will first create a simple
list of employees (List<Employees>) and add some data to it.
C#
    class Program
    {
        static void Main(string[] args)
        {
            List<Employee> empList = new List<Employee>();
            empList.Add(new Employee() { ID = 1, FName = "John", MName = "", LName = "Shields", DOB = DateTime.Parse("12/11/1971"), Sex = 'M' });
            empList.Add(new Employee() { ID = 2, FName = "Mary", MName = "Matthew", LName = "Jacobs", DOB = DateTime.Parse("01/17/1961"), Sex = 'F' });
            empList.Add(new Employee() { ID = 3, FName = "Amber", MName = "Carl", LName = "Agar", DOB = DateTime.Parse("12/23/1971"), Sex = 'M' });
            empList.Add(new Employee() { ID = 4, FName = "Kathy", MName = "", LName = "Berry", DOB = DateTime.Parse("11/15/1976"), Sex = 'F' });
            empList.Add(new Employee() { ID = 5, FName = "Lena", MName = "Ashco", LName = "Bilton", DOB = DateTime.Parse("05/11/1978"), Sex = 'F' });
            empList.Add(new Employee() { ID = 6, FName = "Susanne", MName = "", LName = "Buck", DOB = DateTime.Parse("03/7/1965"), Sex = 'F' });
            empList.Add(new Employee() { ID = 7, FName = "Jim", MName = "", LName = "Brown", DOB = DateTime.Parse("09/11/1972"), Sex = 'M' });
            empList.Add(new Employee() { ID = 8, FName = "Jane", MName = "G", LName = "Hooks", DOB = DateTime.Parse("12/11/1972"), Sex = 'F' });
            empList.Add(new Employee() { ID = 9, FName = "Robert", MName = "", LName = "", DOB = DateTime.Parse("06/28/1964"), Sex = 'M' });
            empList.Add(new Employee() { ID = 10, FName = "Cindy", MName = "Preston", LName = "Fox", DOB = DateTime.Parse("01/11/1978"), Sex = 'M' });
 
            // Printing the List
            Console.WriteLine("\n{0,2} {1,7}    {2,8}      {3,8}      {4,23}      {5,3}",
               "ID", "FName", "MName", "LName", "DOB", "Sex");
            empList.ForEach(delegate(Employee e)
            {
                Console.WriteLine("{0,2} {1,7}    {2,8}      {3,8}      {4,23}    {5,3}",
                    e.ID, e.FName, e.MName, e.LName, e.DOB, e.Sex);
            });
 
            Console.ReadLine();
 
}
 
    class Employee
    {
        public int ID { get; set; }
        public string FName { get; set; }
        public string MName { get; set; }
        public string LName { get; set; }
        public DateTime DOB { get; set; }
        public char Sex { get; set; }
    }
groupby1 How to Use LINQ GroupBy
 
1. List of Employees grouped by the first letter of their FirstName
To display a list of employees group by the first alphabet of their FirstName, use this query
C#
    // Group People by the First Letter of their FirstName
    var grpOrderedFirstLetter = empList.GroupBy(employees =>
        new String(employees.FName[0], 1)).OrderBy(employees => employees.Key.ToString());;
   
    foreach (var employee in grpOrderedFirstLetter)
    {
        Console.WriteLine("\n'Employees having First Letter {0}':", employee.Key.ToString());
        foreach (var empl in employee)
        {
            Console.WriteLine(empl.FName);
        }
    }
 
    Console.ReadLine();
groupby2 How to Use LINQ GroupBy
 
2. List of Employees grouped by the Year in which they were Born
In order to group the employees based on the year in which they were born, use this query
C#
            // Group People by the Year in which they were born           
            var grpOrderedYr = empList.GroupBy(employees => employees.DOB.Year).OrderBy(employees => employees.Key);
 
            foreach (var employee in grpOrderedYr)
            {
                Console.WriteLine("\nEmployees Born In the Year " + employee.Key);
                foreach (var empl in employee)
                {
                    Console.WriteLine("{0,2} {1,7}", empl.ID, empl.FName);
               }
            }
            Console.ReadLine();
groupby3 How to Use LINQ GroupBy
 
3. List of employees grouped by the Year and Month in which they were born
In order to group the employees based on the year and then the month in which they were born, use this query
C#
           // Group people by the Year and Month in which they were born
            var grpOrderedYrMon = empList.GroupBy(employees =>
                new DateTime(employees.DOB.Year, employees.DOB.Month, 1)).OrderBy(employees => employees.Key); ;
 
            foreach (var employee in grpOrderedYrMon)
            {
                Console.WriteLine("\nEmployees Born in Year {0} – Month {1} is/are :", employee.Key.Year, employee.Key.Month);
                foreach (var empl in employee)
                {
                    Console.WriteLine("{0}: {1}", empl.ID, empl.FName);
                }
            }
            Console.ReadLine();
groupby4 How to Use LINQ GroupBy 
4. Total No. Of Birthdays each Year
To get a total of the employees born in the same year, use this query
C#
           // Count people grouped by the Year in which they were born
            var grpCountYrMon = empList.GroupBy(employees => employees.DOB.Year)
                .Select(lst => new {Year = lst.Key, Count = lst.Count()} );
 
            foreach (var employee in grpCountYrMon)
            {
                Console.WriteLine("\n{0} were born in {1}", employee.Count, employee.Year);               
            }
            Console.ReadLine();   
groupby5 How to Use LINQ GroupBy
 
5. Sex Ratio
To find the sex ratio in the company, use this query
C#
            // Sex Ratio
            var ratioSex = empList.GroupBy(ra => ra.Sex)
              .Select( emp => new
              {
                  Sex = emp.Key,
                  Ratio = (emp.Count() * 100) / empList.Count
              });
 
            foreach (var ratio in ratioSex)
            {
                Console.WriteLine("\n{0} are {1}%", ratio.Sex, ratio.Ratio);
            }
            Console.ReadLine(); 

groupby6 How to Use LINQ GroupBy

GD Star Rating
loading...
GD Star Rating
loading...
  • Share/Bookmark
 Page 3 of 9 « 1  2  3  4  5 » ...  Last »