C# function for creating jagged array - c#

I have a problem where I want to create a jagged array. But the size of this jagged array is variable.
Does this work the same way as filling an normal array like this?
int[] terms = new int[400];
for (int runs = 0; runs < 400; runs++)
{
terms[runs] = value;
}
The values I use are defined like this:
public static string[] nodeCassette0 = { "03", "08" };
public static string[] nodeCassette1 = { "04", "09" };
public static string[] nodeCassette2 = { "05", "10" };
public static string[] nodeCassette3 = { "06", "11" };
public static string[] nodeCassette4 = { "07", "12" };
Depending on the size required by the user a new variable nodeCassette needs to be filled according to the required size. The order in which the array is filled is always the same, it starts at 0 and ends at 4.
This should be like that but I don't know how to dynamically create it:
public string[][] nodeCassette =
{
nodeCassette0,
nodeCassette1,
nodeCassette2,
nodeCassette3,
nodeCassette4
};

Here's an example of how to create such a jagged array:
int[] sizes = new int[] { 3, 2, 1, 1, 3 };
int[][] jagged = new int[sizes.Length][];
for (int i = 0; i < sizes.Length; i++)
{
jagged[i] = new int[sizes[i]];
for (int j = 0; j < sizes[i]; j++)
{
jagged[i][j] = (i + 1) * (j + 1);
}
}
That produces:
It's no different with strings:
int[] sizes = new int[] { 3, 2, 1, 1, 3 };
string[][] jagged = new string[sizes.Length][];
for (int i = 0; i < sizes.Length; i++)
{
jagged[i] = new string[sizes[i]];
for (int j = 0; j < sizes[i]; j++)
{
jagged[i][j] = $"{i}_{j}";
}
}

We can use reflexion and Linq.
using System.Reflection;
using System.Linq;
Having this dedicated class to store the arrays by default, as well as initialize a complete list of possible elements, and offer a method to obtain a slice, i.e. a list made up of the first n-elements:
static class DefaultArrays
{
static public string[] NodeCassette0 = { "03", "08" };
static public string[] NodeCassette1 = { "04", "09" };
static public string[] NodeCassette2 = { "05", "10" };
static public string[] NodeCassette3 = { "06", "11" };
static public string[] NodeCassette4 = { "07", "12" };
static public List<string[]> All { get; private set; }
static public List<string[]> Take(int count)
{
return All.Take(count).ToList();
}
static public void Initialize()
{
All = typeof(DefaultArrays).GetFields()
.Where(field => field.FieldType == typeof(string[]))
.OrderBy(field => field.Name.Length)
.ThenBy(field => field.Name)
.Select(field => (string[])field.GetValue(null))
.ToList();
}
static DefaultArrays()
{
Initialize();
}
}
The Initialize method is created this way to possibly allow updating of the entire list in case the arrays are modified at runtime, otherwise the code can be placed directly in the constructor and all arrays marked readonly.
Here is the algorithm for All:
We get all fields of the static class by its type name.
We filter to select only those being of type array of string.
We order by the fields name string length.
Then by this name, thus we finally get for example 1, 2, 30, 40 from 40, 30, 2, 1.
We do a projection to get the reference of the value instead of the field name using it.
And we transform the Linq query into a List<string> object instance to return.
It uses a pseudo-natural numeric sort assuming all arrays are named:
"[same_same][number_without_trailing_left_0]"
Else we can use a custom comparer:
How do I sort strings alphabetically while accounting for value when a string is numeric?
sort string-numbers
Test
var slice = DefaultArrays.Take(3);
string msg = string.Join(Environment.NewLine, slice.Select(item => string.Join(", ", item)));
Console.WriteLine(msg);
Output
03, 08
04, 09
05, 10
Warning
The slice contains a list of references toward original arrays, thus any modification of a cell of an array in this list will be reflected in the matching array in the static class.
Else we need to copy the arrays with Array.Copy instead of using Linq.Take:
static public List<string[]> TakeCopy(int count)
{
var list = new List<string[]>();
foreach ( int index in Enumerable.Range(0, Math.Min(count, All.Count)))
{
int length = All[index].Length;
var array = new string[length];
Array.Copy(All[index], array, length);
list.Add(array);
}
return list;
}

Related

I want to create an array of scene indexes and use it, when i need. The problem is that i don't know how to create the array itself

I did this
public int[] sceneIndex;
public Text[] texts;
IEnumerator ChoosingModes()
{
string[] modes = new string[] { "Cocks", "Tanks", "Cars" };
sceneIndex = new int[] { };
for (int i = 0; i < 5; i++)
{
int x = Random.Range(0, modes.Length);
texts[i].text = modes[x];
sceneIndex[i] = x + 3;
yield return new WaitForSeconds(0.75f);
}
}
It obviously doesn't work, what to do with my in array named 'sceneIndex'?
When you do sceneIndex = new int[] { };, you're locking the length of the length of sceneIndex to 0. Instead, try either sceneIndex = new int[number or scenes]; (locking the length of sceneIndex to the number of scenes you have) or just doing nothing. Since the array is public, you can set the values in the inspector and you won't have to define it in the code.

Is there a way to expand a one-dimensional Array into a 2D Array with the original values in the [0] index of the 2D Array in C#?

I have an Array with Category Names, but now i Need to assign a few Counters to each Category.
Is there a way to expand my 1D-Array to a 2D-Array in C#?
Thanks for helping!
Edit:
PerformanceCounterCategory[] categories;
categories = PerformanceCounterCategory.GetCategories();
string[] categoryNames = new string[categories.Length];
string[] categoryNames_en = new string[categories.Length];
for (int objX = 0; objX < categories.Length; objX++)
{
categoryNames[objX] = categories[objX].CategoryName;
}
Array.Sort(categoryNames);
for (int objX = 0; objX < categories.Length; objX++)
{
Console.WriteLine("{0,4} - {1}", objX + 1, categoryNames[objX]);
}
I have the Array categoryNames with all the Names of the Categories, but in every Category there are a few Counters which i want to assign to their Category somehow...
Unfortunately you can't use Array.Copy since the source and destination array do not have the same dimensions.
Furthermore, you can't expand arrays in C#, since they are initialized with a fixed size.
What you can do is create a new array with a second dimonesion and copy the values over and set the second dimension to a default value.
void Main()
{
int[] sourceCollection = new [] {1,2,3,4,5,6,7} ;
var result = CopyArrayValues(sourceCollection, 2);
result.Dump();
}
//create a new 2d array
T[,] CopyArrayValues<T>(T[] DataSource, int SecondLength)
{
//Initialize the new array
var Target = new T[DataSource.Length, SecondLength];
//Copy values over
for (int i = 0; i < DataSource.Length; i++)
{
Target[i, 0] = DataSource[i];
}
return Target;
}
Output:
If it's ok for you to have array of arrays, you can do something along this pattern:
int[] sourceCollection = new[] { 1, 2, 3, 4, 5, 6, 7 };
int[][] arr = sourceCollection.Select(i => Enumerable.Range(i, 4).ToArray()).ToArray();

Extract integers from 2D Arraylist whose sum is between a range

I'm writing code for a .NETMF application and need to create a function which accepts 2 params int min, int max and returns an array of integers returnedArr from a generated 2D Arraylist arr were the sum of integers inside returnedArr will be between min and max and also I will not know what the size or contents of arr will be prior to calling the method. Only 1 integer per Arraylist inside arr will be selected.
public ArrayList GetNums(int min, int max)
{
//arr will be structured like this
//var arr = new ArrayList
//{
// new ArrayList {10, 34, 56, 60},
// new ArrayList {3, 23, 56, 78, 65, 42},
// new ArrayList {53, 56, 76}
//};
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
var returnedArr = new ArrayList();
var arr = GenerateArraylistValues();
//solution code here...
return returnedArr;
}
A sample would be GetNums(130,140);
Return arraylist could be Arraylist{56,23,53}
Also bear in mind that I'm confined to using Arraylists so I can't use generic lists, I was thinking that some sort of foreach loop would do the job but can't get my head around how this would work since I no idea what the size of arr will be before hand
-----------SAMPLE 'arr' VALUES---------
var arr = new ArrayList
{
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,59,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,90,93,96,99,102},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 60,100,140,180},
new ArrayList { 41,43,45,55,81,83,85,95,121,123,125,135},
new ArrayList { 39,40,41,42,43,44,45,46,47,48,49,53,54,55,59,60,61,77,78,79,80,81,82,83,84,85,86,87,88,89,91,92,94,95,97,98,100,101,115,117,118,119,120,121,122,123,124,125,126,127,129,132,135,138,141},
new ArrayList { 3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,57,63}
};
If the 'arr' is not huge, using recursion and brute force:
public ArrayList GetNums(int min, int max, ArrayList arr)
{
var results = new ArrayList();
//nothing in the arr?
if (arr.Count == 0)
return results;
//arr has only one list inside
if(arr.Count == 1)
{
foreach(int a in (ArrayList)arr[0])
{
if(a >= min && a <= max)
{
var r = new ArrayList();
r.Add(a);
results.Add(r);
}
}
return results;
}
//arr has two or more lists inside
ArrayList firstList = (ArrayList)arr[0];
ArrayList remainingArr = new ArrayList();
for(int i = 1; i < arr.Count; i++)
{
remainingArr.Add(arr[i]);
}
foreach (int a in firstList)
{
var tempResults = GetNums(min - a, max - a, remainingArr);
foreach(ArrayList result in tempResults)
{
var newResult = new ArrayList();
newResult.Add(a);
newResult.AddRange(result);
results.Add(newResult);
}
}
return results;
}
The result is a list of solutions. First valid solution for your example arr is {10, 65, 56}
If it is acceptable to have the same result, of the minimum values, each and every time, then what you could do is to:
start with the smallest value of each sub-array,
sort the remaining values, tracking their source sub-array,
and move up the sorted values until you've met or exceeded the specified min
An example of such functionality (using LINQ for brevity, and converting back to ArrayList) would be as such:
public static ArrayList GetNums(int min, int max)
{
var arr = GenerateArraylistValues();
// Initialize our results with the minimum values from each array.
var results = arr.Cast<ArrayList>().Select(sub => sub.Cast<int>().Min()).ToList();
var others = new List<UnionItem>();
for (int i = 0; i < arr.Count; i++)
{
others = new List<UnionItem>(others
// Concatenate the arrays together.
.Union(((ArrayList)arr[i]).Cast<int>()
// Don't need the min value, which we will start at already. (Optional)
.Where(val => val != results[i])
// Create the UnionItem, to hold the value and the original array source.
.Select(val => new UnionItem(val, i))));
}
// Order our combined values.
others = new List<UnionItem>(others.OrderBy(val => val.Value));
using (var next = others.GetEnumerator())
{
// Progress through the combined values until we (a) meet or exceed min, or (b) run out of values.
while ((results.Sum() < min) && (next.MoveNext()))
{
// Update the list of result values according to the UnionItem source.
results[next.Current.Source] = next.Current.Value;
}
}
// Once through our calculation, check now if we've successfully met the conditions.
int sum = results.Sum();
if (sum >= min && sum <= max)
{
return new ArrayList(results);
}
else
{
// Whatever happens if no valid match.
return new ArrayList();
}
}
private class UnionItem
{
public readonly int Value; // Holds the value from the array.
public readonly int Source; // Holds the index of the source array.
public UnionItem(int value, int source)
{
Value = value;
Source = source;
}
}
I've created the UnionItem class, simply so we can do the tracking of the source array for each value, to substitute back correctly our results.

How to delete a row from a 2d array in c#? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Delete row of 2D string array in C#
i have a 2d string array, I want to delete a specified row from the array.
string[] a = new string[] { "a", "b" }; //dummy string array
int deleteIndex = 1; //we want to "delete" element in position 1 of string
a = a.ToList().Where(i => !a.ElementAt(deleteIndex).Equals(i)).ToArray();
dirty but gives the expected result (foreach through the array to test it)
EDIT missed the "2d array" detail, here is the right code for the job
string[][] a = new string[][] {
new string[] { "a", "b" } /*1st row*/,
new string[] { "c", "d" } /*2nd row*/,
new string[] { "e", "f" } /*3rd row*/
};
int rowToRemove = 1; //we want to get rid of row {"c","d"}
//a = a.ToList().Where(i => !i.Equals(a.ElementAt(rowToRemove))).ToArray(); //a now has 2 rows, 1st and 3rd only.
a = a.Where((el, i) => i != rowToRemove).ToArray(); // even better way to do it maybe
code updated
As has been said above you cant remove from an array.
If you are going to need to remove rows quite often maybe change from using a 2d array to a list containing an array of string. This way you can make use of the remove methods that list implements.
Ok so I said you can't "delete" them. That's still true. You'll have to create a new array instance with enough space for the items you want to keep and copy them over.
If this is a jagged array, using LINQ here could simplify this.
string[][] arr2d =
{
new[] { "foo" },
new[] { "bar", "baz" },
new[] { "qux" },
};
// to remove the second row (index 1)
int rowToRemove = 1;
string[][] newArr2d = arr2d
.Where((arr, index) => index != rowToRemove)
.ToArray();
// to remove multiple rows (by index)
HashSet<int> rowsToRemove = new HashSet<int> { 0, 2 };
string[][] newArr2d = arr2d
.Where((arr, index) => !rowsToRemove.Contains(index))
.ToArray();
You could use other LINQ methods to remove ranges of rows easier (e.g., Skip(), Take(), TakeWhile(), etc.).
If this is a true two-dimensional (or other multi-dimensional) array, you won't be able to use LINQ here and will have to do it by hand and it gets more involved. This still applies to the jagged array as well.
string[,] arr2d =
{
{ "foo", null },
{ "bar", "baz" },
{ "qux", null },
};
// to remove the second row (index 1)
int rowToRemove = 1;
int rowsToKeep = arr2d.GetLength(0) - 1;
string[,] newArr2d = new string[rowsToKeep, arr2d.GetLength(1)];
int currentRow = 0;
for (int i = 0; i < arr2d.GetLength(0); i++)
{
if (i != rowToRemove)
{
for (int j = 0; j < arr2d.GetLength(1); j++)
{
newArr2d[currentRow, j] = arr2d[i, j];
}
currentRow++;
}
}
// to remove multiple rows (by index)
HashSet<int> rowsToRemove = new HashSet<int> { 0, 2 };
int rowsToKeep = arr2d.GetLength(0) - rowsToRemove.Count;
string[,] newArr2d = new string[rowsToKeep, arr2d.GetLength(1)];
int currentRow = 0;
for (int i = 0; i < arr2d.GetLength(0); i++)
{
if (!rowsToRemove.Contains(i))
{
for (int j = 0; j < arr2d.GetLength(1); j++)
{
newArr2d[currentRow, j] = arr2d[i, j];
}
currentRow++;
}
}
Instead of array you can use List or ArrayList class. Using it you can dynamically add element and remove based on your requirement. Array is fixed in size, which can not be manipulated dynamically.
The best way is to work with a List<Type>! The items are ordered in the way the are added to the list and each of them can be deleted.
Like this:
var items = new List<string>;
items.Add("One");
items.Add("Two");
items.RemoveAt(1);

How to remove duplicates from int[][]

I have an array of arrays - information about selection in Excel using VSTO, where each element means start and end selection position.
For example,
int[][] selection = {
new int[] { 1 }, // column A
new int[] { 6 }, // column F
new int[] { 6 }, // column F
new int[] { 8, 9 } // columns H:I
new int[] { 8, 9 } // columns H:I
new int[] { 12, 15 } // columns L:O
};
Could you please help me to find a way, maybe using LINQ or Extension methods, to remove duplicated elements? I mean: F and F, H:I and H:I, etc.
If you want to use a pure LINQ/extension method solution, then you'll need to define your own implementation of IEqualityComparer for arrays/sequences. (Unless I'm missing something obvious, there's no pre-existing array or sequence comparer in the BCL). This isn't terribly hard however - here's an example of one that should do the job pretty well:
public class SequenceEqualityComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return Enumerable.SequenceEqual(x, y);
}
// Probably not the best hash function for an ordered list, but it should do the job in most cases.
public int GetHashCode(IEnumerable<T> obj)
{
int hash = 0;
int i = 0;
foreach (var element in obj)
hash = unchecked((hash * 37 + hash) + (element.GetHashCode() << (i++ % 16)));
return hash;
}
}
The advantage of this is that you can then simply call the following to remove any duplicate arrays.
var result = selection.Distinct(new SequenceEqualityComparer<int>()).ToArray();
Hope that helps.
First you need a way to compare the integer arrays. To use it with the classes in the framework, you do that by making an EquailtyComparer. If the arrays are always sorted, that is rather easy to implement:
public class IntArrayComparer : IEqualityComparer<int[]> {
public bool Equals(int[] x, int[] y) {
if (x.Length != y.Length) return false;
for (int i = 0; i < x.Length; i++) {
if (x[i] != y[i]) return false;
}
return true;
}
public int GetHashCode(int[] obj) {
int code = 0;
foreach (int value in obj) code ^= value;
return code;
}
}
Now you can use an integer array as key in a HashSet to get the unique arrays:
int[][] selection = {
new int[] { 1 }, // column A
new int[] { 6 }, // column F
new int[] { 6 }, // column F
new int[] { 8, 9 }, // columns H:I
new int[] { 8, 9 }, // columns H:I
new int[] { 12, 15 } // columns L:O
};
HashSet<int[]> arrays = new HashSet<int[]>(new IntArrayComparer());
foreach (int[] array in selection) {
arrays.Add(array);
}
The HashSet just throws away duplicate values, so it now contains four integer arrays.

Categories

Resources