Most Frequently asked linq Interview Questions (2024)

author image Hirely
at 04 Jan, 2025

Question: How do you filter data using LINQ?

Answer:

In LINQ, you can filter data using the Where method. The Where method allows you to specify a condition that the elements in a collection must meet to be included in the result. The filter is applied lazily, meaning the data is filtered when the query is executed (not when it is defined).

Syntax:

var filteredCollection = collection.Where(item => condition);
  • collection is the data source (e.g., a list, array, or any IEnumerable).
  • condition is a predicate that defines the filtering logic (a boolean expression).

Example 1: Filtering Numbers

Let’s say you have a list of integers, and you want to filter out only the even numbers.

var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Filter only even numbers
var evenNumbers = numbers.Where(n => n % 2 == 0);

foreach (var number in evenNumbers)
{
    Console.WriteLine(number);
}

Output:

2
4
6
8
10

In this example, the Where method filters the list to include only those numbers that are divisible by 2.


Example 2: Filtering Objects (e.g., Person class)

You can filter more complex types, like a list of Person objects. For example, if you want to filter out people older than 30:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

var people = new List<Person>
{
    new Person { Name = "John", Age = 30 },
    new Person { Name = "Jane", Age = 25 },
    new Person { Name = "Alice", Age = 35 },
    new Person { Name = "Bob", Age = 40 }
};

// Filter people older than 30
var peopleOlderThan30 = people.Where(p => p.Age > 30);

foreach (var person in peopleOlderThan30)
{
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}

Output:

Name: Alice, Age: 35
Name: Bob, Age: 40

In this example, the Where method filters the list of people to include only those with an Age greater than 30.


Example 3: Combining Multiple Conditions

You can combine multiple conditions using logical operators like && (AND), || (OR), etc. For example, to filter people who are both older than 30 and have a name starting with “A”:

var filteredPeople = people.Where(p => p.Age > 30 && p.Name.StartsWith("A"));

foreach (var person in filteredPeople)
{
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}

Output:

Name: Alice, Age: 35

Example 4: Case-Insensitive Filtering

You can also perform case-insensitive filtering using StringComparison.OrdinalIgnoreCase:

var filteredNames = people.Where(p => p.Name.Equals("Alice", StringComparison.OrdinalIgnoreCase));

foreach (var person in filteredNames)
{
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}

Output:

Name: Alice, Age: 35

Example 5: Filtering with Contains (Substrings)

If you want to filter based on a substring (e.g., people whose names contain “Jo”), you can use the Contains method:

var filteredNames = people.Where(p => p.Name.Contains("Jo"));

foreach (var person in filteredNames)
{
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}

Output:

Name: John, Age: 30

Key Points:

  • Where: Filters elements based on a predicate.
  • It returns a new collection of elements that match the condition.
  • Deferred execution: The Where method does not execute until you enumerate over the result (e.g., in a foreach loop, or by calling methods like ToList()).
  • The condition can be any expression that returns a boolean value (true or false).
  • You can filter on simple properties or use more complex conditions involving multiple properties.

Conclusion:

The Where method in LINQ is a powerful and flexible way to filter data based on specific conditions. It works on any IEnumerable collection and is often used to narrow down results before further processing or iteration.

Question: Explain the concept of LINQ method syntax vs. query syntax.

Answer:

LINQ (Language Integrated Query) in C# provides two primary syntaxes for querying data: method syntax and query syntax. Both syntaxes allow you to perform the same operations, but they have different approaches and stylistic differences.

1. Method Syntax (Fluent Syntax)

Method syntax is based on method calls and uses the standard method-chaining approach in C#. It is often referred to as fluent syntax because of its ability to chain multiple method calls together, creating a more concise, functional style of querying.

Method syntax uses LINQ extension methods like Where(), Select(), OrderBy(), etc., which are available on any IEnumerable or IQueryable collection.

Syntax:
var result = collection.Method1(param1)
                       .Method2(param2)
                       .Method3(param3);
Example (Method Syntax):
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Method Syntax: Filter even numbers and multiply them by 2
var result = numbers.Where(n => n % 2 == 0)
                    .Select(n => n * 2)
                    .ToList();

foreach (var number in result)
{
    Console.WriteLine(number); // Output: 4, 8, 12
}

In the above example:

  • Where() is used to filter the even numbers.
  • Select() is used to multiply each number by 2.
  • The ToList() method forces the query to be executed immediately and materializes the result.

2. Query Syntax (SQL-Like Syntax)

Query syntax, on the other hand, is more SQL-like in appearance. It is designed to resemble the structure of SQL queries, making it easier to read and understand, especially for those familiar with SQL. Query syntax uses keywords like from, where, select, orderby, and join.

Syntax:
var result = from item in collection
             where condition
             select item;
Example (Query Syntax):
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Query Syntax: Filter even numbers and multiply them by 2
var result = from n in numbers
             where n % 2 == 0
             select n * 2;

foreach (var number in result)
{
    Console.WriteLine(number); // Output: 4, 8, 12
}

In this example:

  • from specifies the collection and gives it an alias (n).
  • where applies a condition (filtering even numbers).
  • select specifies the transformation (multiplying the number by 2).

Key Differences Between Method Syntax and Query Syntax:

AspectMethod SyntaxQuery Syntax
StructureBased on method calls and chaining.SQL-like syntax with keywords (from, select, etc.).
ChainingUses method chaining (Where(), Select(), OrderBy(), etc.).No method chaining; uses the from, where, select style.
ReadabilityCan be more concise, but might be harder for beginners to understand.More readable for people familiar with SQL.
ExpressivenessMore flexible and can support complex operations (e.g., GroupBy, Join).Some operations are harder to express (e.g., GroupBy, Join).
ExtensibilityMethod syntax allows for more fine-tuned customization and supports more LINQ methods.Some complex operations require more verbose code.
CompilationTranslates to query syntax behind the scenes (e.g., Where becomes from-where internally).Also gets translated to method syntax during compilation.

When to Use Method Syntax vs. Query Syntax:

  • Use Method Syntax when:

    • You need to perform more complex queries, like GroupBy, Join, Aggregate, or SelectMany, as these are often easier to express in method syntax.
    • You want to take advantage of method chaining and functional-style programming.
    • You need a more flexible, customizable way of querying data.
  • Use Query Syntax when:

    • You prefer a SQL-like structure for readability, especially if you are familiar with SQL.
    • You are doing simple queries (e.g., filtering, selecting) where query syntax offers a clear, intuitive approach.

Combining Both Syntaxes:

You can mix method syntax and query syntax in a single LINQ query. For example, you might start with query syntax for the from, where, and select clauses, and then switch to method syntax for more complex operations like OrderBy or Take.

var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

// Combine both query and method syntax
var result = (from n in numbers
              where n % 2 == 0
              select n)
              .OrderBy(n => n) // Method Syntax: Order by the number
              .ToList();

foreach (var number in result)
{
    Console.WriteLine(number); // Output: 2, 4, 6
}

In this case, the filtering (from and where) is done in query syntax, but the sorting (OrderBy) is done using method syntax.


Conclusion:

  • Method Syntax offers a more flexible, fluent style of querying with method chaining and is often used for more complex LINQ operations.
  • Query Syntax provides a SQL-like, declarative syntax that’s easier to read and write for simple queries.
  • Both syntaxes ultimately produce the same results and can be used interchangeably, but it’s often a matter of personal preference or the specific use case. For more complex queries, method syntax may be a better choice, while query syntax might be favored for simplicity and readability in basic scenarios.

Question: What is the First and FirstOrDefault method in LINQ? How are they different?

Answer:

In LINQ, both First and FirstOrDefault are used to retrieve the first element of a sequence that satisfies a specified condition. However, they behave differently when no matching element is found.

1. First Method

The First method returns the first element in a sequence that matches the specified condition or the first element of the sequence if no condition is specified.

  • If the sequence contains at least one element that matches the condition, First will return that element.
  • If no matching element is found or if the sequence is empty, First will throw an InvalidOperationException.
Syntax:
var result = collection.First();

or with a condition:

var result = collection.First(item => item.Condition);
Example (Using First):
var numbers = new List<int> { 1, 2, 3, 4, 5 };

// Find the first even number
var firstEven = numbers.First(n => n % 2 == 0);

Console.WriteLine(firstEven); // Output: 2

If no even number exists, the following will throw an exception:

var firstEven = numbers.First(n => n % 2 == 10); // Throws InvalidOperationException

2. FirstOrDefault Method

The FirstOrDefault method also retrieves the first element that matches the specified condition, but with a key difference: if no matching element is found or if the sequence is empty, it returns the default value for the element’s type instead of throwing an exception.

  • If the sequence contains at least one matching element, it will return that element, just like First.
  • If no matching element is found or the sequence is empty, FirstOrDefault will return:
    • null for reference types (e.g., classes, strings).
    • The default value for value types (e.g., 0 for integers, false for booleans).
Syntax:
var result = collection.FirstOrDefault();

or with a condition:

var result = collection.FirstOrDefault(item => item.Condition);
Example (Using FirstOrDefault):
var numbers = new List<int> { 1, 2, 3, 4, 5 };

// Find the first even number
var firstEven = numbers.FirstOrDefault(n => n % 2 == 0);

Console.WriteLine(firstEven); // Output: 2

If no even number exists:

var firstEven = numbers.FirstOrDefault(n => n % 2 == 10); // Output: 0 (default value for int)

For reference types (e.g., Person class):

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

var people = new List<Person>
{
    new Person { Name = "John", Age = 30 },
    new Person { Name = "Jane", Age = 25 }
};

var person = people.FirstOrDefault(p => p.Name == "Alice"); // Output: null (no matching person)

Key Differences Between First and FirstOrDefault:

AspectFirstFirstOrDefault
Behavior when no matchThrows an InvalidOperationException if no matching element is found.Returns the default value (null for reference types, 0, false, etc., for value types).
Behavior with an empty collectionThrows an InvalidOperationException if the collection is empty.Returns the default value (null or default value for type).
Default ValueNo default value; exception is thrown.Returns default value (e.g., null or 0).
Use CaseUse when you’re certain that the sequence will have at least one matching element.Use when you’re not sure if a matching element will exist, and you want to handle the case gracefully.

Example Showing the Difference:

var numbers = new List<int> { 1, 2, 3, 4, 5 };

// First method will throw an exception if no match is found
try
{
    var result = numbers.First(n => n == 6); // Throws InvalidOperationException
}
catch (InvalidOperationException ex)
{
    Console.WriteLine("Exception: " + ex.Message); // Output: Sequence contains no matching element
}

// FirstOrDefault will return the default value if no match is found
var resultOrDefault = numbers.FirstOrDefault(n => n == 6);
Console.WriteLine(resultOrDefault); // Output: 0 (default value for int)

Conclusion:

  • First: Use when you expect the element to exist and want to throw an exception if it doesn’t.
  • FirstOrDefault: Use when you want to safely handle the case where no element matches, returning a default value (e.g., null or 0) instead of throwing an exception.

These methods are essential tools when working with sequences in LINQ, and choosing the right one depends on whether you want to handle missing data gracefully or catch errors explicitly.

Question: How can you perform joins using LINQ?

Answer:

In LINQ, joins are used to combine data from two or more sequences based on a common key. There are different types of joins in LINQ, such as inner joins, left joins, and group joins. Here’s an explanation of how to perform each type of join.


1. Inner Join

An inner join returns elements from both sequences where there is a match on the joining condition. If an element from the first collection does not have a corresponding element in the second collection, it is excluded from the result.

Syntax:

var result = from item1 in collection1
             join item2 in collection2 on item1.Key equals item2.Key
             select new { item1, item2 };

Example (Inner Join):

var students = new List<Student>
{
    new Student { Id = 1, Name = "John" },
    new Student { Id = 2, Name = "Jane" },
    new Student { Id = 3, Name = "Tom" }
};

var courses = new List<Course>
{
    new Course { StudentId = 1, CourseName = "Math" },
    new Course { StudentId = 2, CourseName = "English" },
    new Course { StudentId = 3, CourseName = "History" }
};

var result = from student in students
             join course in courses on student.Id equals course.StudentId
             select new
             {
                 StudentName = student.Name,
                 CourseName = course.CourseName
             };

foreach (var item in result)
{
    Console.WriteLine($"{item.StudentName} is enrolled in {item.CourseName}");
}

Output:

John is enrolled in Math
Jane is enrolled in English
Tom is enrolled in History

2. Left Join (Left Outer Join)

A left join returns all elements from the left sequence (the first collection) and the matching elements from the right sequence (the second collection). If there is no match in the right sequence, it returns the default value (null for reference types) for the elements of the right sequence.

Syntax:

var result = from item1 in collection1
             join item2 in collection2 on item1.Key equals item2.Key into temp
             from item2 in temp.DefaultIfEmpty()
             select new { item1, item2 };

Example (Left Join):

var students = new List<Student>
{
    new Student { Id = 1, Name = "John" },
    new Student { Id = 2, Name = "Jane" },
    new Student { Id = 3, Name = "Tom" }
};

var courses = new List<Course>
{
    new Course { StudentId = 1, CourseName = "Math" },
    new Course { StudentId = 2, CourseName = "English" }
};

var result = from student in students
             join course in courses on student.Id equals course.StudentId into temp
             from course in temp.DefaultIfEmpty()
             select new
             {
                 StudentName = student.Name,
                 CourseName = course?.CourseName ?? "No course enrolled"
             };

foreach (var item in result)
{
    Console.WriteLine($"{item.StudentName} is enrolled in {item.CourseName}");
}

Output:

John is enrolled in Math
Jane is enrolled in English
Tom is enrolled in No course enrolled

In this example, Tom does not have a matching course, so the CourseName is set to "No course enrolled".


3. Group Join (Join and Group the Results)

A group join returns the elements from the left sequence and groups the matching elements from the right sequence into a collection (IEnumerable). This is useful when you need to return multiple related items from the right collection for each element in the left collection.

Syntax:

var result = from item1 in collection1
             join item2 in collection2 on item1.Key equals item2.Key into temp
             select new { item1, Courses = temp };

Example (Group Join):

var students = new List<Student>
{
    new Student { Id = 1, Name = "John" },
    new Student { Id = 2, Name = "Jane" },
    new Student { Id = 3, Name = "Tom" }
};

var courses = new List<Course>
{
    new Course { StudentId = 1, CourseName = "Math" },
    new Course { StudentId = 1, CourseName = "History" },
    new Course { StudentId = 2, CourseName = "English" }
};

var result = from student in students
             join course in courses on student.Id equals course.StudentId into temp
             select new
             {
                 StudentName = student.Name,
                 Courses = temp
             };

foreach (var item in result)
{
    Console.WriteLine($"{item.StudentName} is enrolled in:");
    foreach (var course in item.Courses)
    {
        Console.WriteLine($"- {course.CourseName}");
    }
}

Output:

John is enrolled in:
- Math
- History
Jane is enrolled in:
- English
Tom is enrolled in:

In this case:

  • John is enrolled in both Math and History.
  • Jane is enrolled in English.
  • Tom is not enrolled in any course, so no courses are listed for him.

4. Cross Join (Cartesian Product)

Although LINQ doesn’t provide a direct syntax for a cross join, you can simulate it by combining each element of one collection with all elements of the other collection. This results in a Cartesian product.

Example (Cross Join):

var numbers = new List<int> { 1, 2, 3 };
var letters = new List<string> { "A", "B", "C" };

var result = from number in numbers
             from letter in letters
             select new { number, letter };

foreach (var item in result)
{
    Console.WriteLine($"{item.number} - {item.letter}");
}

Output:

1 - A
1 - B
1 - C
2 - A
2 - B
2 - C
3 - A
3 - B
3 - C

Here, each number from the first list is combined with every letter from the second list, resulting in a Cartesian product.


Conclusion:

In LINQ, you can perform different types of joins depending on the relationship between the sequences you are working with. Here’s a quick recap:

  • Inner Join: Combines matching elements from both collections.
  • Left Join: Combines all elements from the left collection and matching elements from the right collection, returning null for non-matching elements.
  • Group Join: Joins elements and groups the matching elements from the second collection into a collection.
  • Cross Join: Combines every element from the first collection with every element from the second collection.

By using these join methods, you can handle complex data relationships and easily query data from multiple sources in LINQ.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as linq interview questions, linq interview experiences, and details about various linq job positions. Click here to check it out.

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now