This is an algorithm to return a list of consecutive integer ranges from a list of integers.
The practical use of such an algorithm is to filter lists more efficiently, i.e. rather than check e.g. 1000 items (1..1000; x==1 || x==2 || ... || x==1000), it might be possible to check only 2 items (x >= 1 && x <= 1000).
Does this algorithm have any mistakes, can it be optimized, or are there any other improvements you can suggest?
(As a side note: I know this code does not follow the standard C# naming conventions. I do not like to follow that particular convention; I prefer "snake_case" as it is easier on my eyes.)
Sample output:
(x >= 0 && x <= 1690)
(x >= 13642 && x <= 15331)
(x >= 27283 && x <= 27296)
(x >= 27769 && x <= 27776)
(x >= 28249 && x <= 28256)
(x >= 28729 && x <= 28736)
(x >= 29209 && x <= 29222)
The algorithm (built Visual Studio 2017, C# 7.3, .NET 4.7.2):
public static List<(int from, int to)> get_consecutive_ranges(List<int> fids)
{
if (fids == null || fids.Count == 0) return null;
fids = fids.OrderBy(a => a).Distinct().ToList();
var fids_fast = new List<(int from, int to)>();
var is_conseq_with_last = true;
var start_index = 0;
var end_index = 0;
for (var fids_index = 0; fids_index < fids.Count; fids_index++)
{
var first = fids_index == 0;
var last = fids_index == fids.Count - 1;
if (!first && fids[fids_index - 1] == fids[fids_index] - 1)
{
is_conseq_with_last = true;
}
else if (!first)
{
is_conseq_with_last = false;
}
if (!is_conseq_with_last && !first && !last)
{
end_index = !first && !last ? fids_index - 1 : fids_index;
fids_fast.Add((fids[start_index], fids[end_index]));
start_index = fids_index;
}
else if (last)
{
if (!is_conseq_with_last)
{
if (!first)
{
end_index = fids_index - 1;
}
fids_fast.Add((fids[start_index], fids[end_index]));
start_index = fids_index;
}
end_index = fids_index;
fids_fast.Add((fids[start_index], fids[end_index]));
}
}
fids_fast.ForEach(a => Console.WriteLine($"(x >= {a.@from} && x <= {a.to})"));
return fids_fast;
}
Example use:
// slow:
body = body.Where(a => fids.Contains(a.fid)).ToList();
// fast:
body = body.Where(a => fids_fast.Any(x => a.fid >= x.from && a.fid <= x.to)).ToList();
fids
stand for? Would help me understand what your algorithm is doing better ( at least I would hope ). \$\endgroup\$