Introduction
Most of the time, we think about LINQ in terms of querying the data model. However, it can give a set of alternative solutions to problems that we just drill in in a very primitive and basic way. That is because it is used to perform operations on generics of any data type.
Problem
One task I handled lately was to find the gap in a series of numbers. Let's discuss the first solution that comes into one's mind when he approaches the task at the first stage.
First Solution
To be able to follow the discussion, create a .NET console application and copy the below code inside the program.cs class file.
//################
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
namespace NumberSeriesGapFinder {
class Program {
static void Main(string[] args) {
string inputNumbers;
Console.WriteLine("Enter a set of numbers comma seperated,make sure there is no gap in the set");
Console.WriteLine("for example:1,2,4,5 has a gap while 6,7,8,9 has no gap");
inputNumbers = Console.ReadLine();
try {
CheckGap(inputNumbers);
} catch (Exception ex) {
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
static void CheckGap(string inputNumbers) {
bool GapExist = false;
List < string > SetElements;
SetElements = inputNumbers.Split(",".ToCharArray()[0]).ToList();
for (int i = 0; i < SetElements.Count - 1; i++) //here we are execluding the last element
//if the series ends at 8 it wil not contain 9
{
if (!SetElements.Contains((int.Parse(SetElements.ElementAt(i)) + 1).ToString())) {
GapExist = true;
break;
}
}
if (GapExist) {
Console.WriteLine("Gap Exist in the series,please try again");
inputNumbers = Console.ReadLine();
CheckGap(inputNumbers);
} else {
Console.WriteLine("The series entered has no gaps");
}
}
}
}
//####################
The code above is a very basic solution for the problem, but there are 2 drawbacks after a deeper look,
- It works in a nested loop manner which will keep the memory busy holding the loop index and scanning the whole series against each element
- The numbers should be in ascending order since we do not know the element with the highest value. This element should be excluded from the check since it is the upper boundary of the series
Second Solution
Place the following code below method discussed in solution 1,
//##################
static void CheckGap2(string inputNumbers) {
bool GapExist = false;
int MaxElement;
List < string > SetElements, SetElementsMissingSubSequent;
SetElements = inputNumbers.Split(",".ToCharArray()[0]).ToList();
MaxElement = (from x in SetElements select int.Parse(x)).Max();
SetElementsMissingSubSequent = (from x in SetElements.Where(w => int.Parse(w) < MaxElement) join y in SetElements on(int.Parse(x) + 1) equals(int.Parse(y)) into lj from ljr in lj.DefaultIfEmpty()
//left join
//is a relational algebra operator that
//finds out the elements between two tuples a and b
//which hold the same value for join column a
//as well as the elements in a that have values
//for the join column that do not exist in b
where ljr == null select ljr).ToList();
GapExist = SetElementsMissingSubSequent.Count > 0;
if (GapExist) {
Console.WriteLine("Gap Exist in the series,please try again");
inputNumbers = Console.ReadLine();
CheckGap2(inputNumbers);
} else {
Console.WriteLine("The series entered has no gaps");
}
}
//##########
Notice that we have used LINQ to,
- Perform left join operator between the series and itself (you can refresh your information about left using the comments inside the method). Any number where its subsequent does not exist will satisfy the where condition
- Select the element with the maximum value of the element. The series does not have to be entered in order this way
Now call the method from the main method and try.
Conclusion
Most of the time, we think about LINQ in terms of querying the data model.
However, it can give a set of alternative solutions to problems that we just drill in a very primitive and basic way. That is because it is used to perform operations on generics of any data type.