Index out of range error - c#

I have the following method in my project:
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = new List<double>();
if (start == null)
{
for (var i = 0; i < _pumpOneSpm.Count; i++)
{
if (_date[i].Equals(date))
{
spm.Add(_pumpOneSpm[i]);
spm.Add(_pumpTwoSpm[i]);
}
}
}
else
{
for (var i = 0; i < _pumpOneSpm.Count; i++)
{
if (_date[i].Equals(date) &&
DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0)
{
spm.Add(_pumpOneSpm[i]);
spm.Add(_pumpTwoSpm[i]);
}
}
}
return _dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
}
I'm trying to make the method look a little less unwieldy. I had tried:
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = start == null ? _pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i].Equals(date)).ToList()
: _pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i].Equals(date) &&
DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
return _dailyProjectMaxSpm;
}
But when I ran the program I got an Index out of range. Must be non-negative and less than the size of the collection. Parameter name: index error. Now, I couldn't care less what order the elements are added to the new list, just so long as if the conditions are met, they are added. Could anyone help me out with the error? Thanks.
UPDATE
_date is a list of dates pulled from a database, and _time is a list of timestamps pulled from the same database. All variables with the _ is a list pulled from a database. The Count of each list will always be equal to the Count of each other list.

Like sil said, you're concatenating the two lists, resulting in a list with a larger index range. How about this solution, which uses Enumerable.Range() to produce the indexes, then uses a combined version of your two predicates to filter, and finally flattens the list with SelectMany():
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = Enumerable
.Range(0, _pumpOneSpm.Count)
.Where(x => _date[x].Equals(date) &&
(start == null ||
(DateTime.Compare(_time[x], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[x], DateTime.Parse(end)) < 0)))
.SelectMany(x => new [] { _pumpOneSpm[x], _pumpTwoSpm[x] });
return _dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
}

In original method i is in range from 0 to _pumpOneSpm.Count but now from 0 to
_pumpOneSpm.Count + _pumpTwoSpm.Count
Following results in a list of _pumpOneSpm.Count + _pumpTwoSpm.Count items:
_pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i]
And I cannot see LINQ analogue which would be more clear than your first method example using for loops.

Related

Ask someone's help to explain the performance issue of C# code

I am a C# developer and I am training my coding and algorithm skills on LeetCode.
And now I am handling the problem 5: longest palindromic substring.
I want someone can explain the reason.
My solution version 1 to this problem was:
public string LongestPalindrome(string s)
{
// Step 0: Handles invalid or special cases.
if (string.IsNullOrWhiteSpace(s) ||
s.Length == 1 ||
s.Distinct().Count() == 1 ||
s.Reverse().SequenceEqual(s))
{
return s;
}
if (s.Length == 2)
{
return s.First().Equals(s.Last()) ? s : s.First().ToString();
}
if (s.Distinct().Count() == s.Length)
{
return s.First().ToString();
}
// Step 1: Handles normal cases.
var longestPalindromeSubstring = string.Empty;
for (var index = 0; index < s.Length && s.Length - index > longestPalindromeSubstring.Length; index++)
{
var currentChar = s[index];
var currentCharLastIndex = s.LastIndexOf(currentChar);
if (index == currentCharLastIndex)
{
if (!string.IsNullOrWhiteSpace(longestPalindromeSubstring) ||
longestPalindromeSubstring.Length > 1)
{
continue;
}
longestPalindromeSubstring = currentChar.ToString();
}
var currentCharIndexes = new Stack<int>();
for (var nextIndex = index + 1; nextIndex <= currentCharLastIndex; nextIndex++)
{
if (s[nextIndex] == currentChar)
{
currentCharIndexes.Push(nextIndex);
}
}
while (currentCharIndexes.Any())
{
var relatedIndex = currentCharIndexes.Pop();
var possibleStr = s.Substring(index, relatedIndex - index + 1);
var reversedPossibleStr = new string(possibleStr.Reverse().ToArray());
if (!possibleStr.Equals(reversedPossibleStr) ||
possibleStr.Length < longestPalindromeSubstring.Length ||
possibleStr.Equals(longestPalindromeSubstring))
{
continue;
}
longestPalindromeSubstring = possibleStr;
}
}
return longestPalindromeSubstring;
}
However this solution above was failed to pass the LeetCode validation since the issue: Time Limit Exceeded.
Then I just made a small update, and the solution version 2 passed, the changed part was only adding ToCharArray() method before invoking Reverse() method:
var reversedPossibleStr = new string(possibleStr.ToCharArray().Reverse().ToArray());
if (!possibleStr.Equals(reversedPossibleStr) ||
possibleStr.Length < longestPalindromeSubstring.Length ||
possibleStr.Equals(longestPalindromeSubstring))
{
continue;
}
…………
But I am not sure the reason why it can work, I just guessed that the data in an array will be arranged in a sequence memory space, it may help to improve the performance, could someone explain more detail.
Thank you in advance.
The Reverse method uses EnumerableHelpers.ToArray to fetch the count of the input enumerable. If the enumerable doesn't implement ICollection<T> interface, it will use a list-like approach to creates an array which will extend the array many times. Unfortunately string doesn't implement ICollection<char>, though it knows how many characters it contains, so string.Reverse() is slower than string.ToCharArray().Reverse().

Checking for each item in a list box if its bigger than 5

I have to enter grades to a list box and then to see if they are bigger than 5. And if they are bigger than 5 store the ones who are.
This is what i got so far ..
foreach (var item in listBox.Items)
{
if(Convert.ToInt32(item.ToString())) == 5 )
}
You could use Linq
bool bigger = listBox.Items.OfType<int>().Where(x => x > 5);
It might be usefull to convert the result to a list by using
List<int> filtered = listBox.Items.OfType<int>().Where(x => x > 5).ToList();
You can do this:
var largerThan5 = listBox.Items.Where(I => int.Parse(I.ToString()) > 5).ToList();
You cannot use LINQ as listBox.Items are not implement IEnumerable.
Use this for example:
for (var pos = 0; pos < listBox1.Items.Count; pos++)
{
int value;
if (int.TryParse(listBox1.Items[pos]?.ToString(), out value) && value >= 5)
Debug.WriteLine($"Index: {pos}, Value: {value}");
}

Split a collection of double by size of its contents

I have a collection of numbers (Collection) and it can be any size and contain negative and positive numbers. I am trying to split it up based on some criteria. starting at the first number in the collection I want to make a collection while that number is above -180 and below 180. Any numbers above 180 will go in a new collection or any numbers below -180 will go in an new collection. If the numbers become within the acceptable parameters again those will go in a new collection again. the problem is the collections need to stay in order.
For example.
Take a collection of 100:
the first 50 is between 180 and -180.
the next 20 are below -180
the next 20 are above 180
the last 10 are between 180 and -180
From the collection above I should now have 4 separate collection in the same order as the original 1 collection.
First collection numbers in original order between 180 and -180
second collection numbers in original order below -180
third collection numbers in original order above 180
fourth collection numbers in original order between 180 and -180
I have made an attempt, what I have doesn't work and is a nasty mess of if statements. I don't know linq very well but I think there may be a more elegant solution using that. Can anyone help me out here either with showing me how to create a linq statement or suggestions on how to get my if statements to work if that is the best way.
Collection<Tuple<Collection<double>, int>> collectionOfDataSets = new Collection<Tuple<Collection<double>, int>>();
Collection<double> newDataSet = new Collection<double>();
for (int i = 0; i < dataSet.Count; i++) {
if (dataSet[i] < 180 && dataSet[i] > -180) {
newDataSet.Add(dataSet[i]);
} else {
Tuple<Collection<double>, int> lastEntry = collectionOfDataSets.LastOrDefault(b => b.Item2 == i--);
if (lastEntry != null){
lastEntry.Item1.Add(dataSet[i]);
}
double lastInLastCollection = collectionOfDataSets.ElementAtOrDefault(collectionOfDataSets.Count).Item1.Last();
if (newDataSet.Count > 0 && lastInLastCollection!= dataSet[i]){
collectionOfDataSets.Add(new Tuple<Collection<double>, int>(newDataSet, i));
}
newDataSet = new Collection<double>();
}
}
Thank you in advance for any assistance.
Your example is complicated. I'll first state and solve a simpler problem, then use the same method to solve your original problem.
I want to split a list of numbers into contiguous groups of even and odd numbers. For example, given the list 2,2,4,3,6,2 I would split it into three groups [2,2,4], [3], [6,2]
This can be done concisely with a GroupAdjacentBy method
> var numbers = new List<int>{2,2,4,3,6,2};
> numbers.GroupAdjacentBy(x => x % 2)
[[2,2,4], [3], [6,2]]
To solve your problem, simply replace the even-odd classifying function above with your classification function:
> var points = new List<int>{-180,180};
> var f = new Func<int,int>(x => points.BinarySearch(x));
> var numbers = new List<int>{6,-50,100,190,200,20};
> numbers.GroupAdjacentBy(f)
[[6,-50,100], [190,200], [20]]
If you need the collections to be updated as soon as the values change why don;t you use properties? Something like
// your original collection
public IList<double> OriginalValues; //= new List<double> { -1000, 5, 7 1000 };
public IList<double> BelowMinus180
{
get { return OriginalValues.Where(x => x < -180).ToList().AsReadOnly(); }
}
public IList<double> BetweenMinus180And180
{
get { return OriginalValues.Where(x => x >= -180 && x <= 180).ToList().AsReadOnly(); }
}
public IList<double> Above180
{
get { return OriginalValues.Where(x => x > 180).ToList().AsReadOnly(); }
}
public static List<List<T>> PartitionBy<T>(this IEnumerable<T> seq, Func<T, bool> predicate)
{
bool lastPass = true;
return seq.Aggregate(new List<List<T>>(), (partitions, item) =>
{
bool inc = predicate(item);
if (inc == lastPass)
{
if (partitions.Count == 0)
{
partitions.Add(new List<T>());
}
partitions.Last().Add(item);
}
else
{
partitions.Add(new List<T> { item });
}
lastPass = inc;
return partitions;
});
}
You can then use:
List<List<double>> segments = newDataSet.PartitionBy(d => d > -180 && d < 180);
How about this possible solution using two passes. In the first pass we find the indices were a change occurs, and in the second pass we do the actual partitioning.
First an auxiliary method to determine the category:
protected int DetermineCategory(double number)
{
if (number < 180 && number > -180)
return 0;
else if (number < -180)
return 1;
else
return 2;
}
And then the actual algorithm:
List<int> indices = new List<int>();
int currentCategory = -1;
for (int i = 0; i < numbers.Count; i++)
{
int newCat = DetermineCategory(numbers[i]);
if (newCat != currentCategory)
{
indices.Add(i);
currentCategory = newCat;
}
}
List<List<double>> collections = new List<List<double>>(indices.Count);
for (int i = 1; i < indices.Count; ++i)
collections.Add(new List<double>(
numbers.Skip(indices[i - 1]).Take(indices[i] - indices[i - 1])));
Here is a new answer based on the new info you provided. I hope this time I will be closer to what you need
public IEnumerable<IList<double>> GetCollectionOfCollections(IList<double> values, IList<double> boundries)
{
var ordered = values.OrderBy(x => x).ToList();
for (int i = 0; i < boundries.Count; i++)
{
var collection = ordered.Where(x => x < boundries[i]).ToList();
if (collection.Count > 0)
{
ordered = ordered.Except(collection).ToList();
yield return collection.ToList();
}
}
if (ordered.Count() > 0)
{
yield return ordered;
}
}
One method with linq. Untested but should work
var firstSet = dataSet.TakeWhile(x=>x>-180&&x<180);
var totalCount = firstSet.Count();
var secondSet = dataSet.Skip(totalCount).TakeWhile(x=>x<-180);
totalCount+=secondSet.Count();
var thirdSet = dataSet.Skip(totalCount).TakeWhile(x=>x>180);
totalCount += thirdSet.Count();
var fourthSet = dataSet.Skip(totalCount);

Using LINQ to select item in List<T> and add integer to populate new List<T>

Lets say I have List<string> = new List<string>() {"20","26","32"}
I want to create a new List based on the first number in the previous list and it should have the same number of elements in it. I will be adding a certain number to that first number and so on and so on. As an example, using 6 as the number to add I would get 20,26,32. The resulting list will be List. The number 6 is a class wide property.
The issue comes if I have a list of "N","N","32"
I need to produce the same list of 20,26,32 but I have to use the last number to work out the others.
If I had "N","26","N" I would have to use the middle number to work out the others.
The N represents no data in the input list and it will always be this character
In summary, I need to produce a new list with the same number of elements as the input list and it must take the first or next numerical element to produce the resulting list using a specified number to add/subtract values to.
I wondered if LINQ's aggregate function might be able to handle it but got a bit lost using it.
Examples:
"20","26","32" = 20,26,32
"N","26","32" = 20,26,32
"N","N","32" = 20,26,32
"20","26","N" = 20,26,32
What about something like this:
var n = 6;
List<string> strList = new List<string>() {"20","26","32"};
// list can also be {null, "26", null} , {null, "N", "32"} ,
// {"N", "26", null } etc...
var list = strList.Select(s =>
{
int v;
if(string.IsNullOrEmpty(s) || !int.TryParse(s,out v))
return (int?)null;
return v;
});
var firstValidVal = list.Select((Num, Index) => new { Num, Index })
.FirstOrDefault(x => x.Num.HasValue);
if(firstValidVal == null)
throw new Exception("No valid number found");
var bases = Enumerable.Range(0, strList.Count).Select(i => i * n);
int startVal = firstValidVal.Num.Value - bases.ElementAt(firstValidVal.Index);
var completeSequence = bases.Select(x => x + startVal);
It sounds like you want a function which will
Take a List<int> as input
Make the first element of the original list the first element of the new list
New list has same number of elements as original
Remaining numbers are the first element + a value * position
If so then try the following
static bool TryGetFirstNumber(List<string> list, out number, out index) {
for (var i = 0; i < list.Count; i++) {
var cur = list[0];
if (!String.IsNullOrEmpty(cur) && Int32.TryParse(cur, out number)) {
index = i;
return true;
}
}
number = 0;
index = 0;
return false;
}
static List<T> TheFunction(List<string> list, int increment) {
var newList = new List<int>();
int first;
int index;
if (TryGetFirstNumber(list, out first, out index)) {
first -= index * increment;
} else {
first = 0;
}
newList.Add(first);
for (var i = 1; i < list.Length; i++) {
newList.Add(first + increment);
increment += increment;
}
return newList;
}
For LINQ purposes, I sometimes resort to writing a parse method that returns an int?as the result so that I can return null when it fails to parse. Here's a complete LINQPad implementation that illustrates this and the positional select (taking an approach otherwise similar to digEmAll's):
void Main()
{
var n = 6;
var items = new List<string>
// {"20","N", "N"};
// {"N", "26", "N"};
{"N", "N", "32"};
var first = items
.Select((v,index) => new { val = Parse(v), index })
.First(x => x.val.HasValue);
int start = first.val.Value - n * first.index;
List<string> values = items
.Select((x,i) => (i * n + start).ToString())
.ToList();
}
int? Parse(string strVal)
{
int ret;
if (int.TryParse(strVal, out ret))
{
return ret;
}
return null;
}
Seems like a lot of work to do something kinda simple. Here is a non linq approach.
private List<int> getVals(List<string> input, int modifier)
{
if (input == null) return null; if (input.Count < 1) return null;
foreach (var s in input)
{
int i;
try{i = Convert.ToInt32(s);}
catch{continue;}
var returnList = new List<int>(input.Count);
for (int n = 0; n < input.Count;n++ )returnList[n] = ((n - input.IndexOf(s)) * modifier) + i;
return returnList;
}
return null;
}
DevGeezer's answer, but without the cruft.
But I still learned alot!
static List<String> genlist2(List<String> list, int interval)
{
if (list == null) return null;
var vali = list
.Select((x, i) => x != "N" ? new {val = Convert.ToInt32(x), i } : null)
.First(x => x != null);
if (vali == null) return list.ToList();
return Enumerable.Range(0, list.Count)
.Select(x => (vali.val - (vali.i - x) * interval).ToString())
.ToList();
}

Sudoku algorithm in C#

I need one liner (or close to it) that verifies that given array of 9 elements doesn't contain repeating numbers 1,2,3,...,9. Repeating zeroes do not count (they represent empty cells).
The best I have came out so far is:
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.Join(a, i => i, j => j, (x, y) => x)
.GroupBy(y => y).Where(g => g.Key > 0 && g.Count() > 1).Count() == 0;
If you don't want to solve my problems :), could you at least tell if the above algorithm works correctly?
And, yes, a have read this one.
This is about 50-250 times faster than a LINQ solution (depending on how early the duplicate is found):
public static bool IsValid(int[] values) {
int flag = 0;
foreach (int value in values) {
if (value != 0) {
int bit = 1 << value;
if ((flag & bit) != 0) return false;
flag |= bit;
}
}
return true;
}
Lucky for you I built a sudoku solver myself not too long ago :) The whole thing was about 200 lines of C#, and it would solve the toughest puzzles I could find line in 4 seconds or less.
Performance probably isn't that great due to the use of .Count, but it should work:
!a.Any(i => i != 0 && a.Where(j => j != 0 && i == j).Count > 1)
Also, the j != 0 part isn't really needed, but it should help things run a bit faster.
[edit:] kvb's answer gave me another idea:
!a.Where(i => i != 0).GroupBy(i => i).Any(gp => gp.Count() > 1)
Filter the 0's before grouping. Though based on how IEnumerable works it may not matter any.
Either way, For best performance replace .Count > 1 in either of those with a new IEnumerable extension method that looks like this:
bool MoreThanOne(this IEnumerable<T> enumerable, Predictate<T> pred)
{
bool flag = false;
foreach (T item in enumerable)
{
if (pred(item))
{
if (flag)
return true;
flag = true;
}
}
return false;
}
It probably won't matter too much since arrays are limited to 9 items, but if you call it a lot it might add up.
!a.GroupBy(i => i).Any(gp => gp.Key != 0 && gp.Count() > 1)
This is an old question, but I recently was pointed to a 1 line solution using Oracle's custom SQL for doing tree-like structures. I thought it would be nice to convert this into Linq.
You can read more on my blog about how to Solve Sudoku in 1 line of Linq
Here is the code:
public static string SolveStrings(string Board)
{
string[] leafNodesOfMoves = new string[] { Board };
while ((leafNodesOfMoves.Length > 0) && (leafNodesOfMoves[0].IndexOf(' ') != -1))
{
leafNodesOfMoves = (
from partialSolution in leafNodesOfMoves
let index = partialSolution.IndexOf(' ')
let column = index % 9
let groupOf3 = index - (index % 27) + column - (index % 3)
from searchLetter in "123456789"
let InvalidPositions =
from spaceToCheck in Enumerable.Range(0, 9)
let IsInRow = partialSolution[index - column + spaceToCheck] == searchLetter
let IsInColumn = partialSolution[column + (spaceToCheck * 9)] == searchLetter
let IsInGroupBoxOf3x3 = partialSolution[groupOf3 + (spaceToCheck % 3) +
(int)Math.Floor(spaceToCheck / 3f) * 9] == searchLetter
where IsInRow || IsInColumn || IsInGroupBoxOf3x3
select spaceToCheck
where InvalidPositions.Count() == 0
select partialSolution.Substring(0, index) + searchLetter + partialSolution.Substring(index + 1)
).ToArray();
}
return (leafNodesOfMoves.Length == 0)
? "No solution"
: leafNodesOfMoves[0];
}
Why do you want a convoluted line of Linq code, rather than wrapping up an efficient implementation of the test in an extension method and calling that?
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.HasNoNonZeroRepeats();
One implementation of NoNonZeroRepeats could be to use the 9 lowest bits of a short to indicate presence of a value in the array, giving an O(length(a)) test with no dynamic memory use. Linq is cute, but unless you're only using it for aesthetic reasons (you don't specifically say that you're writing a sudoku solver using only Linq as an exercise) it seems to be just adding complexity here.
How about:
var itIsOk = a.Where(x => x > 0).Distinct().Count() == a.Where(x => x > 0).Count();
Reasoning: First create an enumeration without 0s. Out of the remaining numbers, if its distinct list is the same length as the actual list, then there are no repeats.
or:
If the list of unique numbers is smaller than the actual list, then you must have a repeated number.
This is the one-liner version. The a.Where(x=>x>0) list could be factored out.
var nonZeroList = a.Where(x => x > 0).ToList();
var itIsOk = nonZeroList.Distinct().Count() == nonZeroList.Count();
I usually frown on solutions that involve captured variables, but I had an urge to write this:
bool hasRepeating = false;
int previous = 0;
int firstDuplicateValue = a
.Where(i => i != 0)
.OrderBy(i => i)
.FirstOrDefault(i =>
{
hasRepeating = (i == previous);
previous = i;
return hasRepeating;
});
if (hasRepeating)
{
Console.WriteLine(firstDuplicateValue);
}
For brevity if not performance, how about
var itIsOk = a.Sum() == a.Distinct().Sum();
The following is simple and fast.
if a.Select(i => Math.Pow(2, i - 1)).ToArray().Sum()==511 ...

Categories

Resources