Why is my array index out-of-bounds in this algorithm? - c#

So I'm doing a little practice that is self-explanatory in the commented code below
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static int[,] GetPairs ( int [] arr )
{
// given an array arr of unique integers, returns all the pairs
// e.g. GetPairs(new int [] { 1, 2, 3, 4, 5 }) would return
// { {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3}, {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 5} }
int n = (arr.Length * (arr.Length - 1))/2; // number of pairs unique pairs in an array of unique ints
if ( n < 1 ) return new int[0,2] {}; // if array is empty or length 1
int[,] pairs = new int[n,2]; // array to store unique pairs
// populate the pairs array:
for ( int i = 0, j = 0; i < arr.Length; ++i )
{
for ( int k = i + 1; k < arr.Length; ++k )
{
pairs[j,0] = arr[i];
pairs[j,1] = arr[k];
++j;
}
}
return pairs;
}
public static void Main()
{
int [] OneThroughFour = new int [4] { 1, 2, 3, 4 };
int [,] Pairs = GetPairs(OneThroughFour);
for ( int i = 0; i < Pairs.Length; ++i )
{
Console.WriteLine("{0},{1}",Pairs[i,0],Pairs[i,1]);
}
}
}
and the error I'm getting is
[System.IndexOutOfRangeException: Index was outside the bounds of the
array.]
in the loop
for ( int i = 0; i < Pairs.Length; ++i )
{
Console.WriteLine("{0},{1}",Pairs[i,0],Pairs[i,1]);
}
which doesn't make any sense to me. What is out-of-bounds? Surely not the i, for it is in the range 0, 1, ..., Pairs.Length - 1. Surely not the 0 or 1, for those are valid indices.
Also, is it possible to do this better than O(n^2) and is there a way with .NET that is more compact and efficient?

For two dimensional arrays, the Length property returns the length of the first dimension multiplied by the length of the second dimension. In your case, this is equal to 2 * n
What you want, as far as I can tell is to loop through the first dimension.
Use the GetUpperBound method like this:
for (int i = Pairs.GetLowerBound(0); i <= Pairs.GetUpperBound(0); ++i)
{
//...
}

Related

How shall I Quickly compare two generic lists and it's contents for checking if they are identical?

//Here I have a List of Lists
List<List<T>> SelectionList = new List<List<T>>();
//My current code to compare lists
for(int i = 0; i < SelectionList.Count; i++)
{
for(int j = 0; j < SelectionList.Count; j++)
{
if (SelectionList[i].Equals(SelectionList[j]))
{
SelectionList.Remove(SelectionList[j]);
}
}
}
//Note: The above code supposedly works, in cases where the contents of both the lists are ordered ie., they are in same index, but in my lists they might be same but list contents are shuffled. in this case it fails to identify.
//Basically I need to remove any repetitions of same list in my list of lists;
If (and only if) the following is true:
Your individual lists do not contain any duplicates
The type T of your list elements implements IComparable and GetHashCode() correctly
Then you can remove each list that matches an earlier list like so (note that you must traverse the list backwards when removing items from the end of it otherwise the loop indices could go out of range):
for (int i = lists.Count - 1; i > 0; i--)
{
for (int j = i - 1; j >= 0; j--)
{
if (!lists[i].Except(lists[j]).Any())
{
lists.RemoveAt(i);
break;
}
}
}
The important line here is: !lists[i].Except(lists[j]).Any().
Let's break it down:
lists[i].Except(lists[j]): - This produces a sequence of all the elements of lists[i] that are NOT in lists[j], regardless of order.
Thus if all of the items in lists[j] are also in lists[j], this will produce an empty sequence; otherwise, it will produce a non-empty sequence.
The .Any() will return true for a non-empty sequence, and false for an empty sequence.
So lists[i].Except(lists[j]).Any() will return false if the items are the same in each list and true if they differ.
This is the opposite of what we want for the lists.RemoveAt() so we just negate the result, giving the final code !lists[i].Except(lists[j]).Any().
Compilable console app:
using System;
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main()
{
var lists = new List<List<int>>
{
new() {1, 2, 3, 4, 5}, // [0]
new() {2, 3, 4, 5, 6}, // [1]
new() {3, 4, 5, 6, 7}, // [2]
new() {5, 4, 3, 2, 1}, // [3] Dupe of [0]
new() {4, 5, 6, 7, 8}, // [4]
new() {6, 5, 4, 3, 2}, // [5] Dupe of [1]
new() {5, 6, 7, 8, 9}, // [6]
new() {3, 4, 5, 2, 1}, // [7] Dupe of [0]
new() {6, 7, 8, 9, 0} // [8]
};
for (int i = lists.Count - 1; i > 0; i--)
{
for (int j = i - 1; j >= 0; j--)
{
if (!lists[i].Except(lists[j]).Any())
{
lists.RemoveAt(i);
break;
}
}
}
for (int i = 0; i < lists.Count; ++i)
{
Console.WriteLine(string.Join(", ", lists[i]));
}
}
Try it on DotNetFiddle: https://dotnetfiddle.net/nWnOcP
If, for each list, each possible value appears at most once in the list, you could use a Dictionary<T,int> to store how often an element appears. Then you perform the following steps:
Iterate over the lists, and, for each list, do the following: For each list element k, check if the dictionary contains it as a key. If it does not, then add key k with value 1 to your dictionary. If it does, then increment the value for key k by 1.
Iterate over the dictionary's elements and check that all values are 2 (if you have two lists) or n (if you have n lists).
Your way is not correct, as you said, try this:
you should iterate the following procedure over your list-Of-Lists;
private bool Compare(List<T> List1,List<T> List2)
{
var infirstNotSecond = list1.Except(list2).ToList();
var insecondNotFirst = list2.Except(list1).ToList();
return !infirstNotSecond.Any() && !insecondNotFirst.Any();
}

Operate LINQ queries on 'vertical' rather than 'horizontal' space

I can't figure out how to do this, if even possible.
An example:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {4, 5, 3},
new int[] {1, 2, 3}
};
int[] avgArray = myArrays.//Some LINQ statement to average every Nth element in the second dimension (essentially "flatten" the array)
//avgArray == {2, 3, 3}
To do this so far, I can only think of:
int ndDimLen = myArrays.GetLength(1);
int[] avgArray = new int[ndDimLen];
myArrays.Select(
arr => arr.Select( (n, i) => avgArray[i] += n )
);
avgArray = avgArray.Select( n => n / ndDimLen ).ToArray();
But this defeats the purpose, and isn't a particularly good idea on jagged arrays...
Also, I'd definitely like to avoid transposition, as it's quite a slow operation when operating on large arrays!
Thank you for your time!
You could iterate throught the [Columns] index while a [Row].Length reports that it contains a [Column] in the dimension whose values you need to average.
(Using the terms Column and Row for simplicity, as a visual aid)
An example, using Linq's .Average() to compute the average value of the sequence:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {4, 5, 3},
new int[] {1, 2, 3},
};
int column = 2;
double avg = myArrays.Select((arr, i) => myArrays[i][column]).Average();
Result: 3
With a more complex structure, we need to verify whether the current [Column] contains a value:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {3, 4, 5},
new int[] {3, 4},
new int[] {1, 2, 3, 4},
new int[] {1},
new int[] {4, 5, 3}
};
int column= 2;
double? avg = myArrays.Select((arr, i) =>
((arr.Length > column) ? myArrays?[i][column] : null)).Average();
Result Column 1: { 1, 3, 3, 1, 1, 4 } => 2.1666666...
Result Column 2: { 2, 4, 4, 2, 5 } => 3.4
Result Column 3: { 3, 5, 3, 3 } => 3.5
Result Column 4: { 4 } => 4
Same method, applied to all the [Columns]:
var Averages = Enumerable.Range(0, myArrays.Max(Arr => Arr.Length))
.Select(col => myArrays
.Select((arr, idx) =>
((arr.Length > col) ? myArrays?[idx][col] : null))
.Average()).ToList();
Enumerable.Range gives some flexibility.
The code above generates a series of int elements starting from 0 and incrementing the value to the number of Colums in the Array (Max(Arr => Arr.Length) selects the Array's Row containing the higher number of elements).
So, you could average the numbers in the first Column only (Index = 0) with:
var Averages = Enumerable.Range(0, 1).Select( ... )
or from Columns 1 to 3 (Indexes 1 to 3):
var Averages = Enumerable.Range(1, 3).Select( ... )
Yes, it is possible, but not on this object.
Basically, myArrays is an array of arrays, so LINQ only sees one row at a time, you cannot make it to see columns, because it's just not how it works.
What you could do, is to transpose this "table" first, that is change places of columns and rows. How to do it has already been discussed here so I will just refer you to it.
Using knowledge how to transpose it, you can make a method that will do it, and use LINQ on it, like:
Transpose(myArray).Select(predicate);
You didn't specify what you want if the arrays have unequal length:
int[][] myArrays =
{
new int[] {1, 2},
new int[] {4, 5, 3, 7, 5, 3, 4, 5, 1},
new int[] {1, 2, 3}
};
Let's assume your arrays all have the same length.
If you plan to use this functionality regularly, consider writing an extension function for two dimensional arrays. See Extension Methods Demystified
public static IEnumerable<int> ToVerticalAverage(this int[][] array2D)
{
if (array2D == null) throw new ArgumentNullException(nameof(array2D);
// if input empty: return empty
if (array2D.Any())
{ // there is at least one row
// check number of columns:
int nrOfColumns = array2D.First().Length;
if (!array2D.All(row => row.Length == nrOfColumns)
{
// TODO: decide what to do if arrays have unequal length
}
// if here, at least one row, all rows have same number of columns
for(int columNr = 0; columNr < nrOfColumns; ++columNr)
{
yield return array2D.Select(row => row[i]).Average();
}
}
// else: no rows, returns empty sequence
}
Usage:
int[][] myInputValues = ...
IEnumerable<int> averageColumnValues = myInputValues.ToVerticalAverage();
If you have several functions where you need the values of the columns, write an extension function to fetch the columns (= transpose the matrix)
public static IEnumerable<IEnumerable<int>> Transpose(this int[][] array2D)
{
// TODO: check input
int nrOfColumns = array2D.First().Length;
for(int columNr = 0; columNr < nrOfColumns; ++columNr)
{
yield return array2D.Select(row => row[columnNr];
}
}
public static IEnumerable<int> ToVerticalAverage(this int[][] array2D)
{
// TODO: check input
foreach (IEnumerable<int> column in array2D.Transpose())
{
yield return column.Average();
}

How to create a variable number of columns for a DataGrid table?

How can I create a DataGrid table with a variable number of columns?
Example: Assuming we have a list of integer lists List<List<int>>. All inner lists have the same length n. Now I would like to create a row per integer list and for each integer an extra column.
For example: For the two integer lists {1, 2, 3} and 4, 5, 6 the DataGad would look like this:
1 | 2 | 3
--+---+---
4 | 5 | 6
Normally, I create an own class for my DataGrid row elements, like
class MyDataGridRecord {
public int first { get; set; }
public int second { get; set; }
...
}
But since I do not know how many columns I have, I can not write such a class with a fixed number of fields.
I suppose you can do something like this:
var list = new List<List<int>>
{
new List<int>() {2, 3, 4, 5},
new List<int>() {2, 3, 4, 5},
new List<int>() {2, 3, 4, 5},
new List<int>() {2, 3, 4, 5}
};
var columnCount = list[0].Count;
for (int i = 0; i < columnCount; i++)
{
dataGridView1.Columns.Add(i.ToString(),"Column " + i+1);
}
for (int k = 0; k < list.Count; k++)
{
dataGridView1.Rows.AddCopy(0);
}
for (int k = 0; k < list.Count; k++)
{
for (int i = 0; i < list[k].Count; i++)
{
dataGridView1.Rows[k].Cells[i].Value = list[k][i];
}
}

fastest way to create Average array from multiple arrays of numbers

I have multiple input arrays of Float all of equal size and a single dimension. I want to create a single output Array that contains the average of all the input arrays.
e.g.
//input arrays
float[] array1 = new float[] { 1, 1, 1, 1 };
float[] array2 = new float[] { 2, 2, 2, 2 };
float[] array3 = new float[] { 3, 3, 3, 3 };
float[] array4 = new float[] { 4, 4, 4, 4 };
//the output should be
float[2.5, 2.5, 2.5, 2.5]
I would also like to calculate the standard deviation of the input arrays to.
What is the fastest approach to do this task?
Thanks in advance.
Pete
LINQ to the rescue
This anwer details how to use LINQ to achieve the goal, with maximum reusability and versatility as the major objective.
Take 1 (package LINQ into a method for convenience)
Take this method:
float[] ArrayAverage(params float[][] arrays)
{
// If you want to check that all arrays are the same size, something
// like this is convenient:
// var arrayLength = arrays.Select(a => a.Length).Distinct().Single();
return Enumerable.Range(0, arrays[0].Length)
.Select(i => arrays.Select(a => a.Skip(i).First()).Average())
.ToArray();
}
It works by taking the range [0..arrays.Length-1] and for each number i in the range it calculates the average of the ith element of each array. It can be used very conveniently:
float[] array1 = new float[] { 1, 1, 1, 1 };
float[] array2 = new float[] { 2, 2, 2, 2 };
float[] array3 = new float[] { 3, 3, 3, 3 };
float[] array4 = new float[] { 4, 4, 4, 4 };
var averages = ArrayAverage(array1, array2, array3, array4);
This can already be used on any number of arrays without modification. But you can go one more step and do something more general.
Take 2 (generalizing for any aggregate function)
float[] ArrayAggregate(Func<IEnumerable<float>, float> aggregate, params float[][] arrays)
{
return Enumerable.Range(0, arrays[0].Length)
.Select(i => aggregate(arrays.Select(a => a.Skip(i).First())))
.ToArray();
}
This can be used to calculate any aggregate function:
var output = ArrayAggregate(Enumerable.Average, array1, array2, array3, array4);
Instead of Enumerable.Average you can substitute any method, extension method, or anonymous function -- which is useful, as there's no built-in standard deviation aggregate function and also this way the ArrayAggregate function is very versatile. But we can still do better.
Take 3 (generalizing for any aggregate function and any type of array)
We can also make a generic version that works with any built-in type:
T[] ArrayAggregate<T>(Func<IEnumerable<T>, T> aggregate, params T[][] arrays)
{
return Enumerable.Range(0, arrays[0].Length)
.Select(i => aggregate(arrays.Select(a => a.Skip(i).First())))
.ToArray();
}
As you can probably tell, this is not the fastest code to do the job. If your program spends all day calculating averages, use something more close to the metal. However, if you want reusability and versatility I don't think you can do much better than the above.
The fastest way in terms of performance, unless you'd like to unroll the for loop is
float[] sums = new float[4];
for(int i = 0; i < 4; i++)
{
sums[i] = (array1[i]+ array2[i] + array3[i] + array4[i])/4;
}
static void Main()
{
float[] array1 = new float[] { 1, 1, 1, 1 };
float[] array2 = new float[] { 2, 2, 2, 2 };
float[] array3 = new float[] { 3, 3, 3, 3 };
float[] array4 = new float[] { 4, 4, 4, 4 };
float[] avg = CrossAverage (array1, array2, array3, array4);
Console.WriteLine (string.Join ("|", avg.Select(f => f.ToString ()).ToArray()));
}
private static float[] CrossAverage (params float [][] arrays)
{
int [] count = new int [arrays[0].Length];
float [] sum = new float [arrays[0].Length];
for (int j = 0; j < arrays.Length; j++)
{
for (int i = 0; i < count.Length; i++)
{
count[i] ++;
sum[i] += arrays[j][i];
}
}
float [] avg = new float [arrays[0].Length];
for (int i = 0; i < count.Length; i++)
{
avg[i] = sum[i] / count[i];
}
return avg;
}
Don't forget bounds checking and divide by 0 checking.
And for the standard deviation after calculating the averages (into the sums array):
// std dev
float[] stddevs = new float[4];
for (int i = 0; i < 4; i++)
{
stddevs[i] += (array1[i] - sums[i]) * (array1[i] - sums[i]);
stddevs[i] += (array2[i] - sums[i]) * (array2[i] - sums[i]);
stddevs[i] += (array3[i] - sums[i]) * (array3[i] - sums[i]);
stddevs[i] += (array4[i] - sums[i]) * (array4[i] - sums[i]);
}
for (int i = 0; i < 4; i++)
stddevs[i] = (float)Math.Sqrt(stddevs[i]/4);
In general, accessing the array directly rather than using LINQ will be a performance win due to allowing the compiler/JIT to optimize. At the very least, array bounds checks can be eliminated and the overhead of using an enumerator will be avoided.

How to delete an element from an array in C#

Lets say I have this array,
int[] numbers = {1, 3, 4, 9, 2};
How can I delete an element by "name"? , lets say number 4?
Even ArrayList didn't help to delete?
string strNumbers = " 1, 3, 4, 9, 2";
ArrayList numbers = new ArrayList(strNumbers.Split(new char[] { ',' }));
numbers.RemoveAt(numbers.IndexOf(4));
foreach (var n in numbers)
{
Response.Write(n);
}
If you want to remove all instances of 4 without needing to know the index:
LINQ: (.NET Framework 3.5)
int[] numbers = { 1, 3, 4, 9, 2 };
int numToRemove = 4;
numbers = numbers.Where(val => val != numToRemove).ToArray();
Non-LINQ: (.NET Framework 2.0)
static bool isNotFour(int n)
{
return n != 4;
}
int[] numbers = { 1, 3, 4, 9, 2 };
numbers = Array.FindAll(numbers, isNotFour).ToArray();
If you want to remove just the first instance:
LINQ: (.NET Framework 3.5)
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int numIndex = Array.IndexOf(numbers, numToRemove);
numbers = numbers.Where((val, idx) => idx != numIndex).ToArray();
Non-LINQ: (.NET Framework 2.0)
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int numIdx = Array.IndexOf(numbers, numToRemove);
List<int> tmp = new List<int>(numbers);
tmp.RemoveAt(numIdx);
numbers = tmp.ToArray();
Edit: Just in case you hadn't already figured it out, as Malfist pointed out, you need to be targetting the .NET Framework 3.5 in order for the LINQ code examples to work. If you're targetting 2.0 you need to reference the Non-LINQ examples.
int[] numbers = { 1, 3, 4, 9, 2 };
numbers = numbers.Except(new int[]{4}).ToArray();
You can also convert your array to a list and call remove on the list. You can then convert back to your array.
int[] numbers = {1, 3, 4, 9, 2};
var numbersList = numbers.ToList();
numbersList.Remove(4);
The code that is written in the question has a bug in it
Your arraylist contains strings of " 1" " 3" " 4" " 9" and " 2" (note the spaces)
So IndexOf(4) will find nothing because 4 is an int, and even "tostring" would convert it to of "4" and not " 4", and nothing will get removed.
An arraylist is the correct way to go to do what you want.
I posted my solution here.
This is a way to delete an array element without copying to another array - just in frame of the same array instance:
public static void RemoveAt<T>(ref T[] arr, int index)
{
for (int a = index; a < arr.Length - 1; a++)
{
// moving elements downwards, to fill the gap at [index]
arr[a] = arr[a + 1];
}
// finally, let's decrement Array's size by one
Array.Resize(ref arr, arr.Length - 1);
}
Removing from an array itself is not simple, as you then have to deal with resizing. This is one of the great advantages of using something like a List<int> instead. It provides Remove/RemoveAt in 2.0, and lots of LINQ extensions for 3.0.
If you can, refactor to use a List<> or similar.
Balabaster's answer is correct if you want to remove all instances of the element. If you want to remove only the first one, you would do something like this:
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int firstFoundIndex = Array.IndexOf(numbers, numToRemove);
if (numbers >= 0)
{
numbers = numbers.Take(firstFoundIndex).Concat(numbers.Skip(firstFoundIndex + 1)).ToArray();
}
As a generic extension, 2.0-compatible:
using System.Collections.Generic;
public static class Extensions {
//=========================================================================
// Removes all instances of [itemToRemove] from array [original]
// Returns the new array, without modifying [original] directly
// .Net2.0-compatible
public static T[] RemoveFromArray<T> (this T[] original, T itemToRemove) {
int numIdx = System.Array.IndexOf(original, itemToRemove);
if (numIdx == -1) return original;
List<T> tmp = new List<T>(original);
tmp.RemoveAt(numIdx);
return tmp.ToArray();
}
}
Usage:
int[] numbers = {1, 3, 4, 9, 2};
numbers = numbers.RemoveFromArray(4);
You can do in this way:
int[] numbers= {1,3,4,9,2};
List<int> lst_numbers = new List<int>(numbers);
int required_number = 4;
int i = 0;
foreach (int number in lst_numbers)
{
if(number == required_number)
{
break;
}
i++;
}
lst_numbers.RemoveAt(i);
numbers = lst_numbers.ToArray();
' To remove items from string based on Dictionary key values.
' VB.net code
Dim stringArr As String() = "file1,file2,file3,file4,file5,file6".Split(","c)
Dim test As Dictionary(Of String, String) = New Dictionary(Of String, String)
test.Add("file3", "description")
test.Add("file5", "description")
stringArr = stringArr.Except(test.Keys).ToArray()
public int[] DeletePart(int position, params int[] numbers)
{
int[] result = new int[numbers.Length - 1];
int z=0;
for (int i = 0; i < numbers.Length; i++)
{
if (position - 1 != i)
{
result[z] = numbers[i];
z++;
}
}
return result;
}
We can delete array elements by using for loops and continue statements:
string[] cars = {"volvo", "benz", "ford", "bmw"};
for (int i = 0; i < cars.Length; i++)
{
if (cars[i] == "benz")
{
continue;
}
Console.WriteLine(cars[i]);
}

Categories

Resources