I’m attempting to write an algorithm that calculates the distance between vertebrae. The text parser already works perfectly in picking out vertebral references (cervical 6, c-6, c6, c six, cervical six).
It currently references a linear string array, and matches Vertebrae to their index, and then subtracts Min
from Max
. The solves 95% of cases.
The issue comes in from two scenarios:
- Distance is not necessarily linear. L5 to Pelvis and L5 to Sacrum are both considered one level.
- Genetic anomalies can produce extra vertebrae. Most people have 12 Thoracic vertebrae, some have up to 14.
If I only needed to solve one or the other, it wouldn’t an issue. I’m now looking at a complicated mess of workarounds to make this work, and I’m certain there is a simpler answer.
private static int CalculateLevelNumber(IEnumerable<string> levels)
{
List<int> levelindexes = new List<int>();
List<string> spinemap = new List<string> { "occiput", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "l1", "l2", "l3", "l4", "l5", "s1", "s2" };
foreach(string level in levels)
{
levelindexes.Add(spinemap.IndexOf(level));
}
return levelindexes.Max() - levelindexes.Min();
}
Here is what I mean by ugly workaround:
private static int CalculateLevelNumber(IEnumerable<string> levels)
{
List<int> levelindexes = new List<int>();
List<string> spinemap = new List<string> { "occiput", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "l1", "l2", "l3", "l4", "l5", "s1", "s2" };
if(levels.Contains("t15"))
{
spinemap.InsertRange(spinemap.IndexOf("t12"), new List<string> { "t13", "t14", "t15" });
}
else if(levels.Contains("t14"))
{
spinemap.InsertRange(spinemap.IndexOf("t12"), new List<string> { "t13", "t14" });
}
else if (levels.Contains("t13"))
{
spinemap.InsertRange(spinemap.IndexOf("t12"), new List<string> { "t13" });
}
foreach (string level in levels)
{
if(level == "pelvis" || level == "ilium")
levelindexes.Add(spinemap.IndexOf("s1"));
else
levelindexes.Add(spinemap.IndexOf(level));
}
return levelindexes.Max() - levelindexes.Min();
}
3
Alright, for starters, I guess I would precompute several spinemap
lists in advance, and keep them immutable during execution of the calculations, instead just picking the right one to use for each case.
To finish up, I’d use array of int
instead of array of string
for the spinemap
s. I’d transform the level
s from string
form to an enum
, and use that enum
to index into spinemap
. The spinemap
arrays would store the int
position directly at each enum level
‘s index.
So, we’d have four(?) spinemap
s as array of int
position indexable by enum level
, precomputed and unmodified during calculation.
There are any number of other possibilities, including defining a class to group names together with positions, which might take a bit more searching, but perhaps be more maintainable. We could also start with a set of easly maintained and readable definitions, and then build the precomputed data structures needed from that so we don’t have to do so much searching during calculation.