I knew the function would include a lot of data processing, but I didn't think it would end up taking minuets to process.
The function in question is fed a jagged 2D array which is made up of Paragraphs > Sentences this is made from a text file fed by the user so can be massive. It takes this array and compares every sentence to each other and saves a score between each sentence which is the number of common words.
This takes forever and I honestly didn't think it would.
My main test text is only 181 sentences long, but this translates to 32.7 thousand values scored in a 2D array.
This matrix of values is then used to calculate and select the most "relevant" sentences from each paragraph, and other things.
The 181 sentence text takes 1min 15seconds to process, a text of only 70 sentences takes 35 seconds, but this is based on number of sentences not words, but it gives you an idea. I dread to think how long it would take on an actual document.
The function in question:
protected void Intersection2DArray()
{
mainSentenceCoord = -1;
for (int x1 = 0; x1 < results.Length; x1++)
{
for (int x2 = 0; x2 < results[x1].Length; x2++)
{
var mainSentencesWords = wordSplit(results[x1][x2]);
secondarySentenceCoord = -1;
mainSentenceCoord++;
for (int y1 = 0; y1 < results.Length; y1++)
{
for (int y2 = 0; y2 < results[y1].Length; y2++)
{
var secondarySentencesWords = wordSplit(results[y1][y2]);
int commonElements = mainSentencesWords.Intersect(secondarySentencesWords).ToList().Count();
secondarySentenceCoord++;
intersectionArray[mainSentenceCoord, secondarySentenceCoord] = commonElements;
}
}
}
}
}
The wordSplit function:
protected List<String> wordSplit(string sentence)
{
var symbols = "£$€#&%+-.";
var punctuationsChars = Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
.Select(i => (char)i)
.Where(c => char.IsPunctuation(c))
.Except(symbols)
.ToArray();
var words = sentence.Split(punctuationsChars)
.SelectMany(x => x.Split())
.Where(x => !(x.Length == 1 && symbols.Contains(x[0])))
.Distinct()
.ToList();
return words;
}
I initially wanted to do this split using one Regex line, but wouldn't figure it out, that may make it faster.
This loops through to select each sentence against each other, this is best I could come up. I'm fine with doing a total overall if it will drastically increase speed.
Edit: Using Moby Disk suggestion heres my new instant code:
Word Split function which is called once now and returns a List of List
public List<List<string>> createWordList()
{
List<List<string>> wordList = new List<List<string>>();
var symbols = "£$€#&%+-.";
var punctuationsChars = Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
.Select(i => (char)i)
.Where(c => char.IsPunctuation(c))
.Except(symbols)
.ToArray();
for (int x1 = 0; x1 < results.Length; x1++)
{
for (int x2 = 0; x2 < results[x1].Length; x2++)
{
var words = results[x1][x2].Split(punctuationsChars)
.SelectMany(x => x.Split())
.Where(x => !(x.Length == 1 && symbols.Contains(x[0])))
.Distinct()
.ToList();
wordList.Add(words);
}
}
return wordList;
}
And the now super slim Intersection Function
protected void intersectionMatrix()
{
List<List<string>> wordList = createWordList();
mainSentenceCoord = -1;
for (var x = 0; x < wordList.Count; x++)
{
secondarySentenceCoord = -1;
mainSentenceCoord++;
for (var y = 0; y < wordList.Count; y++)
{
secondarySentenceCoord++;
intersectionArray[mainSentenceCoord, secondarySentenceCoord] = wordList[x].Intersect(wordList[y]).Count();
}
}
}
See update at the end:
There is some "low-hanging fruit" here that could speed it up a lot with out changing the algorithm itself:
wordSplit() recalculates "punctuationsChars" each time it is called. Do that once up front.
You are calling wordSplit() for the same sentence a N^2 number of times instead of N number of times since it is in both the outer (x1,x2) loop and the inner (y1,y2) loop. You only need to split 181 sentences, not 181^2 number of sentences. So instead, loop through results, call wordSplit once on each sentence, and store that result. If that takes up too much memory, look into memoization (http://en.wikipedia.org/wiki/Memoization) although I think you should be okay since it will only result in about 1 more copy of the text.
You don't need the ToList() after the Intersect(). That creates a list you don't use.
I'm confused as to the values of mainSentenceCoord and secondarySentenceCoord. What are the dimensions of the resulting intersectionArray?
OMG! #1 is it! That sped this up by a factor of 80x. Look at this line:
Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue)
char.MaxValue is 65536. So if N=181, you are looping 181 x 181 x 65536! I just ran the profiler to confirm it: 98.4% of the CPU time is spent in the ToArray() calls in wordSplit.
Related
I get Strings like this from my database:
NaN#Nan#44.20216139610997#45.35340149990988#45.44329482112824#45.1593428796393#NaN#NaN
values = SQLvalues.Split('#'); //produces Array you can see in the picture
(String[] values)
Going on further with strings until it ends with about 10 "NaN" Strings again.
What I am doing now is that I sum up all the values from that one Array.
But there will be about 100 more Arrays after this one and I need to add up for example values[8] from this Array with the one at the same position from the next Array.
hope this visualizes better what I need to do
As I am still an apprentice I don´t have much knowledge on all of this.
I´ve been trying to come with a solution for several hours now but I won´t seem to get anything to work here.
Any help would be great!
My Code:
String[] values;
String returnString = "";
List<Double> valueList = new List<Double>();
DateTime time = (DateTime)skzAdapterText.MinTambourChangedTime();
DataTable profilData = skzAdapterText.LoadValuesText(time);
int rowCount = profilData.Rows.Count;
for (int i = 0; i < rowCount; i++)
{
String SQLvalues = (String)profilData.Rows[i][2];
values = SQLvalues.Split('#');
double summe = 0;
int counter = 0;
foreach (String tmpRow in values)
{
Double value;
if (double.TryParse(tmpRow, NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out value)
&& !double.IsNaN(value))
{
counter++;
summe = summe + value;
}
}
if (summe != 0 && counter != 0)
valueList.Add(summe / counter);
}
The basic sum can be reduced like so:
values = SQLvalues.Split('#');
double sum = values.Where(v => v != "NaN").Select(v => double.Parse(v)).Sum();
For a specific position, say index 8, within many rows:
//Read the data from DB
DataTable profilData = skzAdapterText.LoadValuesText(time);
//parse out the values
var rowValueArrays = // will be a List<double[]>
profilData.Rows.
Select(r => r[2].Split('#').Select(v => v == "NaN"?0.0:double.Parse(v)).ToArray()).
ToList();
// sum the entries at index 8
double sumAt8 = rowValueArrays.Select(r => r[8]).Sum();
You say you are an apprentice, and so the syntax here may be unfamiliar to you and seem difficult to understand. But I want to emphasize the power here. The combination of IEnumerable, lambda expressions, and linq operations reduced the original sample down to two lines of code, and solved the full problem in what is technically three lines (spread out a little for readability). If I wanted to sacrifice any sense of style or maintainability, we could do it in just one line of code.
In short, it is well worth your time to learn how to write code this way. With practice, reading and writing code this way can become easy and greatly increase your speed and capability as a programmer.
I also see attempts to compute an average. Continuing from the end of the previous code:
int countAt8 = rowValuesArrays.Count(r => r[8] != 0.0);
double average = sumAt8 / countAt8;
Finally, I need to point out delimited data like this in a column is an abuse of the database and very poor practice. Schemas like this are considered broken, and need to be fixed.
As you want to sum up the values at the same positions of the arrays, I assume that all these array have the same length. Then first declare the required arrays. You also must probably calculate the average for each array position, so you also need an array for the counter and the averages.
double[] average = null;
int rowCount = profilData.Rows.Count;
if (rowCount > 0) {
string[] values = ((string)profilData.Rows[0][2]).Split('#');
int n = values.Length;
double[] sum = new double[n];
double[] counter = new double[n];
for (int i = 0; i < rowCount; i++) {
values = ((string)profilData.Rows[i][2]).Split('#');
for (int j = 0; j < n; j++) {
if (double.TryParse(values[j], NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture, out double value) && !double.IsNaN(value)) {
counter[j]++;
sum[j] += value;
}
}
}
average = new double[n];
for (int i = 0; i < n; i++) {
if (counter[i] != 0) {
average[i] = sum[i] / counter[i];
}
}
}
You cannot calculate the average while summing up, since you must divide the total sum by the total count. Therefore, I added another loop calculating the averages at each array position after the summing phase.
Assuming I have a list of numbers, which could be any amount, realistically over 15.
I want to separate that list of numbers into three groups depending on their size, small, medium, and large for instance.
What is the best way of achieving this?
I've written out the below, is it necessary to make my own function as per below, or is there anything existing that I can utilise in .NET?
public static List<int> OrderByThree (List<int> list)
{
list.Sort();
int n = list.Count();
int small = n / 3;
int medium = (2 * n) / 3;
int large = n;
// depending if the number is lower/higher than s/m/l,
// chuck into group via series of if statements
return list;
}
Example
Say I have a list of numbers, 1-15 for instance, I want 1-5 in small, 6-10 in medium and 11-15 in large. However I won't know the amount of numbers at the start, no dramas, using list.count I was hoping to divide for my own function.
Since you have the list sorted already, you can use some LINQ to get the results. I'm assuming a right-closed interval here.
list.Sort();
int n = list.Count();
var smallGroup = list.TakeWhile(x => (x <= n / 3)).ToList();
var middleGroup = list.Skip(smallGroup.Count).TakeWhile(x => (x <= (2 * n) / 3)).ToList();
var largeGroup = list.Skip(smallGroup.Count + middleGroup.Count).ToList();
EDIT
As Steve Padmore commented, you probably will want to return a list of lists (List<List<int>>) from your method, rather than just List<int>.
return new List<List<int>> { smallGroup, middleGroup, largeGroup };
This would be a simple way of doing it:
var result = list.GroupBy (x =>
{
if(x <= small) return 1;
if(x <= medium) return 2;
return 3;
});
Or:
var result = list.GroupBy (x => x <= small ? 1 : x <= medium ? 2 : 3);
(This does not require the list to be sorted)
For a given a space separated list of numbers, what is the most effecient way of counting the total pairs of numbers which have a difference of N.
e.g. command line in put would be:
5 2
where 5 is the count of numbers to follow and 2 is the difference required
1 5 3 4 2
the 5 numbers to be considered
Output should be
3
because (5,3), (4,2) and (3,1) all have a diff of 2
I can get this algorithm to work, but is there a more efficient way of doing this if you have large sets of numbers to work with? I have incluced three comparison options and the second one should be better than the third but is there something I'm forgetting which could make it much quicker?
private static void Difference()
{
string[] firstInput = SplitInput(Console.ReadLine());
int numberOfNumbers = int.Parse(firstInput[0]);
int diffOfNumbers = int.Parse(firstInput[1]);
string[] secondInput = SplitInput(Console.ReadLine());
List<int> numbers = secondInput.Select(x => Int32.Parse(x)).ToList();
int possibleCombinations = 0;
// Option 1
foreach (int firstNumber in numbers)
{
List<int> compareTo = numbers.GetRange(numbers.IndexOf(firstNumber) + 1, numbers.Count - numbers.IndexOf(firstNumber) - 1);
foreach (int secondNumber in compareTo)
{
int diff = firstNumber - secondNumber;
if (Math.Abs(diff) == diffOfNumbers)
{
possibleCombinations++;
}
}
}
// Option 2
foreach (int firstNumber in numbers)
{
if (numbers.Contains(firstNumber + diffOfNumbers))
{
possibleCombinations++;
}
}
// Option 3
foreach (int firstNumber in numbers)
{
foreach (int secondNumber in numbers)
{
int diff = firstNumber - secondNumber;
if(Math.Abs(diff) == diffOfNumbers)
{
possibleOptions++;
}
}
}
Console.WriteLine(string.Format("Possible number of options are: {0}", possibleCombinations));
Console.ReadLine();
}
private static string[] SplitInput(string input)
{
return input.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
If duplicate numbers are not allowed or to be ignored (only count unique pairs), you could use a HashSet<int>:
HashSet<int> myHashSet = ...
int difference = ...
int count;
foreach (int number in myHashSet)
{
int counterpart = number - difference;
if (myHashSet.Contains(counterpart))
{
count++;
}
}
Given the constraints of the problem, where N is the "count of numbers to follow" [1..N], and M is the difference (N=5 and M=2 in the example), why not just return N - M ?
This is done easily with LINQ, allowing for duplicates:
var dict = numbers.GroupBy(n => n).ToDictionary(g => g.Key, g => g.Count());
return dict.Keys.Where(n => dict.ContainsKey(difference-n)).Select(n => dict[difference - n]).Sum();
In the first line we create a dictionary where the keys are the distinct numbers in the input list (numbers) and the values are how many times they appear.
In the second, for each distinct number in the list (equivalent to the keys of the dictioanry) we look to see if the dictionary contains a key for the target number. If so, we add the number of times that target number appeared, which we previously stored as the value for that key. If not we add 0. Finally we sum it all up.
Note in theory this could cause arithmetic overflows if there's no bound other than Int.MinValue and Int.MaxValue on the items in the list. To get around this we need to do a "safe" check, which first makes sure that the difference won't be out of bounds before we try to calculate it. That might look like:
int SafeGetCount(int difference, int number, Dictionary<int,int> dict)
{
if(difference < 0 && number < 0 && int.MinValue - difference > number)
return 0;
if(difference > 0 && number > 0 && int.MaxValue - difference < number)
return 0;
return dict.ContainsKey(difference-number) ? dict[difference - number] : 0;
}
Update
There are a couple of things note entirely clear from your question, like whether you actually want to count duplicate pairs multiple times, and does swapping the numbers count as two different pairs. e.g. if (1,4) is a pair, is (4,1)? My answer above assumes that the answer to both of those questions is yes.
If you don't want to count duplicate pairs multiple times, then go with the HashSet solution from other answers. If you do want to count duplicate pairs but don't want to count twice by swapping the values in the pair, you have to get slightly more complex. E.g.:
var dict = numbers.GroupBy(n => n).ToDictionary(g => g.Key, g => g.Count());
var sum = dict.Keys.Where(n => n*2 != difference)
.Where(n => dict.ContainsKey(difference-n))
.Select(n => dict[difference - n]).Sum()/2;
if(n%2 == 0)
{
sum += dict.ContainsKey(n/2) ? dict[n/2] : 0
}
return sum;
how about sorting the list then iterating over it.
int PairsWithMatchingDifferenceCount(
IEnumerable<int> source,
int difference)
{
var ordered = source.OrderBy(i => i).ToList();
var count = ordered.Count;
var result = 0;
for (var i = 0; i < count - 1; i++)
{
for (var j = i + 1; j < count; j++)
{
var d = Math.Abs(ordered[j] - ordered[i]);
if (d == difference)
{
result++;
}
else if (d > difference)
{
break;
}
}
}
return result;
}
so, as per the example you would call it like this,
PairsWithMatchingDifferenceCount(Enumerable.Range(1, 5), 2);
but, if the sequence generation is a simple as the question suggests why not just.
var m = 5;
var n = 2;
var result = Enumerable.Range(n + 1, m - n)
.Select(x => Tuple.Create(x, x - n)).Count();
or indeed,
var result = m - n;
I have a comma delimited text file that contains 20 digits separated by commas. These numbers represent earned points and possible points for ten different assignments. We're to use these to calculate a final score for the course.
Normally, I'd iterate through the numbers, creating two sums, divide and be done with it. However, our assignment dictates that we load the list of numbers into two arrays.
so this:
10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85
becomes this:
int[10] earned = {10,20,30,40,45,50,20,45,85};
int[10] possible = {10,20,35,50,50,50,20,90,85};
Right now, I'm using
for (x=0;x<10;x++)
{
earned[x] = scores[x*2]
poss [x] = scores[(x*2)+1]
}
which gives me the results I want, but seems excessively clunky.
Is there a better way?
The following should split each alternating item the list into the other two lists.
int[20] scores = {10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85};
int[10] earned;
int[10] possible;
int a = 0;
for(int x=0; x<10; x++)
{
earned[x] = scores[a++];
possible[x] = scores[a++];
}
You can use LINQ here:
var arrays = csv.Split(',')
.Select((v, index) => new {Value = int.Parse(v), Index = index})
.GroupBy(g => g.Index % 2,
g => g.Value,
(key, values) => values.ToArray())
.ToList();
and then
var earned = arrays[0];
var possible = arrays[1];
Get rid of the "magic" multiplications and illegible array index computations.
var earned = new List<int>();
var possible = new List<int>();
for (x=0; x<scores.Length; x += 2)
{
earned.Add(scores[x + 0]);
possible.Add(scores[x + 1]);
}
This has very little that would need a text comment. This is the gold standard for self-documenting code.
I initially thought the question was a C question because of all the incomprehensible indexing. It looked like pointer magic. It was too clever.
In my codebases I usually have an AsChunked extension available that splits a list into chunks of the given size.
var earned = new List<int>();
var possible = new List<int>();
foreach (var pair in scores.AsChunked(2)) {
earned.Add(pair[0]);
possible.Add(pair[1]);
}
Now the meaning of the code is apparent. The magic is gone.
Even shorter:
var pairs = scores.AsChunked(2);
var earned = pairs.Select(x => x[0]).ToArray();
var possible = pairs.Select(x => x[1]).ToArray();
I suppose you could do it like this:
int[] earned = new int[10];
int[] possible = new int[10];
int resultIndex = 0;
for (int i = 0; i < scores.Count; i = i + 2)
{
earned[resultIndex] = scores[i];
possible[resultIndex] = scores[i + 1];
resultIndex++;
}
You would have to be sure that an equal number of values are stored in scores.
I would leave your code as is. You are technically expressing very directly what your intent is, every 2nd element goes into each array.
The only way to improve that solution is to comment why you are multiplying. But I would expect someone to quickly recognize the trick, or easily reproduce what it is doing. Here is an excessive example of how to comment it. I wouldn't recommend using this directly.
for (x=0;x<10;x++)
{
//scores contains the elements inline one after the other
earned[x] = scores[x*2] //Get the even elements into earned
poss [x] = scores[(x*2)+1] //And the odd into poss
}
However if you really don't like the multiplication, you can track the scores index separately.
int i = 0;
for (int x = 0; x < 10; x++)
{
earned[x] = scores[i++];
poss [x] = scores[i++];
}
But I would probably prefer your version since it does not depend on the order of the operations.
var res = grades.Select((x, i) => new {x,i}).ToLookup(y=>y.i%2, y=>y.x)
int[] earned = res[0].ToArray();
int[] possible = res[1].ToArray();
This will group all grades into two buckets based on index, then you can just do ToArray if you need result in array form.
here is an example of my comment so you do not need to change the code regardless of the list size:
ArrayList Test = new ArrayList { "10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85" };
int[] earned = new int[Test.Count / 2];
int[] Score = new int[Test.Count / 2];
int Counter = 1; // start at one so earned is the first array entered in to
foreach (string TestRow in Test)
{
if (Counter % 2 != 0) // is the counter even
{
int nextNumber = 0;
for (int i = 0; i < Score.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(Score[i])))
{
nextNumber = i;
break;
}
}
Score[nextNumber] = Convert.ToInt32(TestRow);
}
else
{
int nextNumber = 0;
for (int i = 0; i < earned.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(earned[i])))
{
nextNumber = i;
break;
}
}
earned[nextNumber] = Convert.ToInt32(TestRow);
}
Counter++
}
Im trying to get specific lines from a file and put them in a another string or maybe if we can put it in anothe textbox it wont be a prob :P
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[c];
c = c + 2;
}
I get a :
Index was outside the bounds of the array.
If you want to get every second line.
Change your loop to
//Odd Lines
for (int x = 0; x < msglines.Length; x = x + 2)
{
this.textBox5.Text += msglines[x];
}
//Even Lines
for (int x = 1; x < msglines.Length; x = x + 2)
{
this.textBox5.Text += msglines[x];
}
As was pointed out in the comments, you can shorten x = x + 2 to x += 2
And in the interest of LinqY Goodness...
//ODDS
msgLines
.Where((str, index) => index % 2 == 0)
.ToList()
.ForEach(str => textBox1.Text += String.Format("{0}\r\n", str));
//EVENS
msgLines
.Where((str, index) => index % 2 == 1)
.ToList()
.ForEach(str => textBox1.Text += String.Format("{0}\r\n", str));
your loop is controlled by x, but you're indexing by c [hence you need logic to prevent c getting greater than size of the array]
Because you are increasing the line index (c) by 2 each time; just use x:
this.textBox5.Text = msglines[x];
Of course, from a loop this will result in just the last line being shown. What line is it you actually want to show?
Edit re comment; in which case, simply:
StringBuilder sb = new StringBuilder();
for (int x = 1; x < msglines.Length; x+=2)
{
sb.AppendLine(msglines[x]);
}
this.textBox5.Text = sb.ToString();
In your for loop, you are using c. You need to use x. Could I suggest that you have a look at the reference for for.
Try this instead...
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[x];
}
Then you should use X as an index, with a step of 2, instead of 1.
Try this
string[] msglines;
msglines = System.IO.File.ReadAllLines(#"C:\Users\xA\Desktop\MESSAGES.txt");
for (int x = 0; x < msglines.Length; x++)
{
this.textBox5.Text = msglines[x++];
}
You say you want all odd-numbered lines in the TextBox, but your loop will only show the last line, as you overwrite the contents on each pass.
To show all odd-numbered lines, separated by line breaks:
string lineSep = "";
for (int x = 0; x < msglines.Length; x += 2)
{
this.textBox5.Text += lineSep + msglines[x];
lineSep = "\r\n";
}
For simplicity I'll use an example of taking every other character from a string, but the case of taking every other line from an array of strings is analogous.
Lets take "Hello" as an example for your msglines string
(source: javabat.com)
and let us say that your global variable c i initialized to 0 before you enter the for loop. Your msglines.Lenght will be 5. In the the fourth iteration through the loop (x == 3) you are going to try to access msglines[6], which is outside of the bounds of the array, hence the error.
You probably wanted something along the lines of
int x = 0;
while(x <= msglines.Lenght){
this.textBox5.Text += msglines[x];
x = x + 2;
}
or
for(x=0; x <= msglines.Lenght ; x+=2){
this.textBox5.Text += msglines[x];
}
To get the odd lines you would start with x initialized to 1.
As for which of the two fully equivalent versions above to use, I would suggest using the one that is more readable to you. In my experience that is always the better choice.
You have a double backslash in the ReadAllLines() call, causing it to fail opening the file.
Also, you are using c as an array index, it looks like you want x
The code i wrote is exactly how I want it to be.....
I actually want every odd line from my file to be sent to the textbox.and yeah P.S C initializes from 1
Besides the already mentioned indexing problems of c versus x, you are also overwriting textBox5.Text on every iteration, so you'll only ever see the last line. It seems somehow unlikely to be intended behaviour. You might want something like this instead:
this.textBox5.Text += msglines[x]; // note x instead of c
Or if you really want everything and the +2 was a typo in itself you could do this without any loop:
this.textBox5.Text = String.Join( "\n", msglines );
The following function will return an IEnumerable that gives the odd numbered lines in a file:
private IEnumerable<string> GetOddLines(string fileName)
{
string[] lines = File.ReadAllLines(fileName);
IEnumerator allLines = lines.GetEnumerator();
while (allLines.MoveNext())
{
yield return (string)allLines.Current;
if (!allLines.MoveNext())
{
break;
}
}
}
If you want the even numbered lines, just add a call to allLines.MoveNext() before the while loop.
You need to loop the array with Length -1. Array of 45 Length will only index to 44.