Converting a Jagged Array to a multidimensional array [duplicate] - c#

This question already has answers here:
Converting jagged array to 2D array C#
(4 answers)
Closed 3 years ago.
I am converting a list within a list to an int[][] using:
int[][] preConvertInts = processedList.Select(array => array.ToArray().ToArray()) as int[][];
I am returning an int[,] in my method. What is the best way to convert an int[][] to an int[,]?
Edit: method
public static int[,] GetIntArrayInts(string dataString){
string data = dataString;
data = data.Replace(Environment.NewLine, "\n");
List<List<int>> processedList = new List<List<int>>();
string[] rows = data.Split('\n');
foreach (string row in rows){
string[] columns = row.Split(',');
List<int> ints = new List<int>();
foreach (string column in columns){
if (int.TryParse(column, out int tileGid)) ints.Add(tileGid);
}
processedList.Add(ints);
}
int[][] preConvertInts = processedList.Select(array => array.ToArray().ToArray()) as int[][];
int[,] processedIntArray = new int[preConvertInts[0].Length, preConvertInts[1].Length];
for (int i = 0; i < preConvertInts.Length; i++){
int[] intArray = preConvertInts[i];
for (int j = 0; j < intArray.Length; j++){
processedIntArray[i, j] = preConvertInts[i][j];
}
}
return processedIntArray;
}

What is the best way to convert an int[][] to an int[,]?
it is the one that is described in this post. Yours will actually also work if all sub-arrays have the same Length. But to cite you:
Unfortunately, my array is not rectangular. – Luna
Then it would not make much sense to try to convert it. Unless you loose values or you add values to make the dimensions of all sub arrays equal.
But your problem in the code is not this conversion but this one:
I am converting a list within a list to an int[][] using:
int[][] preConvertInts = processedList.Select(array => array.ToArray().ToArray()) as int[][];
This is wrong. You will get null for preConvertInts! if you check the return value of the Select call:
You can see that it returns IEnumerable<int[]> and not int[][]. Casting it with as int[][]; does not work and masks only the fact that the 2 types are different from the compiler. What you do there is to convert each sublist into an array and then convert (the already converted array) simply again into an array.
You need to make the select in the proper way:
int [][] preConvertInts = processedList.Select(x=>x.ToArray()).ToArray();
Explanation:
1) in the first step you collect all sublists and convert each one into an array: Select(x=>x.ToArray())
2) now this call returns an IEnumerable<int[]> which you need to convert again to an array:
Select(x=>x.ToArray()).ToArray();
^^
||
note the dot behind the closing parentesis of the Select call

Jagged Array
public static T[,] ToMultiArray<T>(this IList<T[]> arrays)
{
var length = arrays[0].Length;
var result = new T[arrays.Count, length];
for (var i = 0; i < arrays.Count; i++)
{
var array = arrays[i];
if (array.Length != length)
{
throw new ArgumentException("Misaligned arrays");
}
for (var j = 0; j < length; j++)
{
result[i, j] = array[j];
}
}
return result;
}
Multidimensional Array
public static T[][] ToJaggedArray<T>(this IList<T[]> arrays)
{
var result = new T[arrays.Count][];
for (var i = 0; i < arrays.Count; i++)
{
var array = arrays[i];
var length = array.Length;
result[i] = new T[length];
for (var j = 0; j < length; j++)
{
result[i][j] = array[j];
}
}
return result;
}
Usage
var preConvertInts = list.ToJaggedArray();
or
var preConvertInts = list.ToMultiArray();
Update
this IList<T[]> arrays this method is for lists which contain arrays,
to fit OP's example it should be (this IList<List<T>> arrays) – Mong
Zhu
Jagged Array
public static T[][] ToJaggedArray<T>(IList<List<T>> arrays)
{
var result = new T[arrays.Count][];
for (var i = 0; i < arrays.Count; i++)
{
var array = arrays[i];
var length = array.Count;
result[i] = new T[length];
for (var j = 0; j < length; j++)
{
result[i][j] = array[j];
}
}
return result;
}
Multidimensional Array
public static T[,] ToMultiArray<T>(IList<List<T>> arrays)
{
var length = arrays[0].Count;
var result = new T[arrays.Count, length];
for (var i = 0; i < arrays.Count; i++)
{
var array = arrays[i];
if (array.Count != length)
{
throw new ArgumentException("Misaligned arrays");
}
for (var j = 0; j < length; j++)
{
result[i, j] = array[j];
}
}
return result;
}
Note : Totally untested

Related

Create a new array using loops in C# without built-in methods

I'm studying for my first test in C# (beginner). I have a problem with assingments where I'm supposed to create a new array using loops. For example this task where the task is to write a method that recieves a sentence(string) and a letter(char). The method must then identify at which index positions the letter
occurs at in the sentence and then place these positions in a
array. For example, we have the short sentence "Hello world!"
and the letter 'o' then the array should contain 4 (the index position of the first
instance) and 7 (the index position of the second instance).
I'm not allowed to use built-in methods except for .Length, Console.WriteLine..
You can see my code below. It is not working at all. I want it to print out "4, 7, "
static void Main(string[] args)
{
int[] result = IndexesOfChar("Hello world", 'o');
for(int i = 0; i<result.Length; i++)
{
Console.Write(result[i] + ", ");
}
}
static int[] IndexesOfChar(string sentence, char letter)
{
int count = 0;
int[] newArr = new int[count];
for(int i =0; i < sentence.Length; i++)
{
if(sentence[i] == letter)
{
newArr[count] = i;
count++;
}
}
return newArr;
}
The problem is that you don't know the array Length beforehand. So you have to compute count and
only then create the array:
static int[] IndexesOfChar(string sentence, char letter)
{
// Required array length computation:
int count = 0;
for (int i = 0; i < sentence.Length; i++)
if (sentence[i] == letter)
count++;
// We know count, we are ready to create the array:
int[] newArr = new int[count];
// Finally, we fill in the array
// let do not re-use count, but declare separate index variable
int index = 0;
for (int i = 0; i < sentence.Length; i++)
if (sentence[i] == letter)
newArr[index++] = i;
return newArr;
}
Your task is not a good example for arrays, usually we put List<T> when we don't know size:
using System.Linq;
...
static int[] IndexesOfChar(string sentence, char letter) {
List<int> result = new List<int>();
for (int i = 0; i < sentence.Length; ++i)
if (sentence[i] == letter)
result.Add(i); // <- unlike array we can just Add a new item
// create an array from list with a help of Linq
return result.ToArray();
}
It is not working, because in the method IndexesOfChar, you create an array with a length of count (that is at that point is zero). You can't modify an array's length once you declared it.
If you can't use any built in methods, I suggest you to declare the newArr as a list. This is what you should fill the indexes into, then create an array, and fill the list's values into that array with another for loop.
Unlike type List, you can't change the size of an array, so you can't do newArr[count] = i; because the size of newArr is 0. Instead if you only want to use arrays, you can reassign newArr with its old value + the new integer :
static void Main(string[] args)
{
int[] result = IndexesOfChar("Hello world", 'o');
for(int i = 0; i<result.Length; i++)
{
Console.Write(result[i] + ", ");
}
}
static int[] IndexesOfChar(string sentence, char letter)
{
int count = 0;
int[] newArr = new int[count];
for(int i =0; i < sentence.Length; i++)
{
if(sentence[i] == letter)
{
var updateArr = new int[newArr.Length + 1];
for (int j = 0; j < newArr.Length; j++)
{
updateArr[j] = newArr[j];
}
updateArr[newArr.Length] = i;
newArr = updateArr;
count++;
}
}
return newArr;
}

Remove Nulls from string[,]

I have a string array defined in c# as
string[,] options = new string[100,3];
Throughout the code it gets populated with data but not always filled.
So if I have 80 parts of it filled and 20 parts of it not filled. The 20 parts have nulls in them or 60 nulls at the end. Is there an easy way to resize the array so that after filling it the array is the same as
String[,] options = new string[80,3];
It would have to be resized based on the position of the first set of 3 nulls it found.
If this was a jagged array I would have done
options = options.Where(x => x != null).ToArray();
The method is quite long, because it has to check every row twice...
public static string[,] RemoveEmptyRows(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we count the non-emtpy rows
int nonEmpty = 0;
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty++;
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty, length2];
for (int i1 = 0, i2 = 0; i2 < nonEmpty; i1++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i1, j] != null)
{
// If the i1 row is not empty, we copy it
for (int k = 0; k < length2; k++)
{
strs2[i2, k] = strs[i1, k];
}
i2++;
break;
}
}
}
return strs2;
}
Use it like:
string[,] options = new string[100, 3];
options[1, 0] = "Foo";
options[3, 1] = "Bar";
options[90, 2] = "fiz";
options = RemoveEmptyRows(options);
As suggested by Alexei, there is another way of doing this:
public static string[,] RemoveEmptyRows2(string[,] strs)
{
int length1 = strs.GetLength(0);
int length2 = strs.GetLength(1);
// First we put somewhere a list of the indexes of the non-emtpy rows
var nonEmpty = new List<int>();
for (int i = 0; i < length1; i++)
{
for (int j = 0; j < length2; j++)
{
if (strs[i, j] != null)
{
nonEmpty.Add(i);
break;
}
}
}
// Then we create an array of the right size
string[,] strs2 = new string[nonEmpty.Count, length2];
// And we copy the rows from strs to strs2, using the nonEmpty
// list of indexes
for (int i1 = 0; i1 < nonEmpty.Count; i1++)
{
int i2 = nonEmpty[i1];
for (int j = 0; j < length2; j++)
{
strs2[i1, j] = strs[i2, j];
}
}
return strs2;
}
This one, in the tradeoff memory vs time, chooses time. It is probably faster, because it doesn't have to check every row twice, but it uses more memory, because it puts somewhere a list of the non-empty indexes.
I went for all rows until you find an row with all null values:
Needs some clean up and will obviously remove non-null rows that occur after the first all null row. The requirement wasn't too clear here
EDIT: Just seen the comment clarifying requirement to remove all null rows - I've tweaked the below to avoid downvotes but a more comprehensive answer is already accepted (and is more efficient) :)
void Main()
{
string[,] options = new string[100,3];
options[0,0] = "bleb";
options[1,1] = "bleb";
options[2,0] = "bleb";
options[2,1] = "bleb";
options[3,2] = "bleb";
options[4,1] = "bleb";
string[,] trimmed = TrimNullRows(options);
Console.WriteLine(trimmed);
}
public string[,] TrimNullRows(string[,] options)
{
IList<string[]> nonNullRows = new List<string[]>();
for (int x = 0; x < options.GetLength(0); x++)
{
bool allNull = true;
var row = new string[options.GetLength(1)];
for (int y = 0; y < options.GetLength(1); y++)
{
row[y] = options[x,y];
allNull &= options[x,y] == null;
}
if (!allNull)
{
nonNullRows.Add(row);
}
}
var optionsTrimmed = new string[nonNullRows.Count, options.GetLength(1)];
for (int i=0;i<nonNullRows.Count;i++)
{
for (int j=0;j<options.GetLength(1);j++)
{
optionsTrimmed[i, j] = nonNullRows[i][j];
}
}
return optionsTrimmed;
}
You can also get yourself some helpers to convert between jagged and multi-dimensional representations. This is pretty silly, of course, but for arrays as small as the ones you're showing (and also, very sparse arrays), it'll be fine.
void Main()
{
string[,] options = new string[100,3];
options[3, 1] = "Hi";
options[5, 0] = "Dan";
var results =
options
.JagIt()
.Where(i => i.Any(j => j != null))
.UnjagIt();
results.Dump();
}
static class Extensions
{
public static IEnumerable<IEnumerable<T>> JagIt<T>(this T[,] array)
{
for (var i = 0; i < array.GetLength(0); i++)
yield return GetRow(array, i);
}
public static IEnumerable<T> GetRow<T>(this T[,] array, int rowIndex)
{
for (var j = 0; j < array.GetLength(1); j++)
yield return array[rowIndex, j];
}
public static T[,] UnjagIt<T>(this IEnumerable<IEnumerable<T>> jagged)
{
var rows = jagged.Count();
if (rows == 0) return new T[0, 0];
var columns = jagged.Max(i => i.Count());
var array = new T[rows, columns];
var row = 0;
var column = 0;
foreach (var r in jagged)
{
column = 0;
foreach (var c in r)
{
array[row, column++] = c;
}
row++;
}
return array;
}
}
The JagIt method is pretty simple of course - we'll just iterate over the rows, and yield the individual items. This gives us an enumerable of enumerables, which we can use in LINQ quite easily. If desired, you could transform those into arrays, of course (say, Select(i => i.ToArray()).ToArray()).
The UnjagIt method is a bit more talkative, because we need to create the target array with the correct dimensions first. And there's no unyield instruction to simplify that :D
This is pretty inefficient, of course, but that isn't necessarily a problem. You could save yourself some of the iterations by keeping the inner enumerable an array, for example - that will save us having to iterate over all the inner items.
I'm mostly keeping this as the memory-cheap, CPU-intensive alternative to #xanatos' memory-intensive, CPU-cheap (relatively).
Of course, the main bonus is that it can be used to treat any multi-dimensional arrays as jagged arrays, and convert them back again. General solutions usually aren't the most efficient :D
Yet another variant with linq
static string[,] RemoveNotNullRow(string[,] o)
{
var rowLen = o.GetLength(1);
var notNullRowIndex = (from oo in o.Cast<string>().Select((x, idx) => new { idx, x })
group oo.x by oo.idx / rowLen into g
where g.Any(f => f != null)
select g.Key).ToArray();
var res = new string[notNullRowIndex.Length, rowLen];
for (int i = 0; i < notNullRowIndex.Length; i++)
{
Array.Copy(o, notNullRowIndex[i] * rowLen, res, i * rowLen, rowLen);
}
return res;
}

Convert a List containing List<double> to single flatten array

to convert a list to array[,] there is code:
double[,] arr = new double[list.Count, list[0].Length];
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list[0].Length; j++)
{
arr[i, j] = list[i][j];
}
}
I want to convert it to flatten array so Using the fact
Flattened array index computation
array[(Y coordinate * width) + X coordinate]
2D array index computation
array[Y coordinate, X coordinate]
code changes to
double[] arr = new double[list.Count * list[0].Length];
for (int i = 0; i < list.Count ; i++)
{
for (int j = 0; j < list[0].Length; j++)
{
arr[i] = list[i * list[0].Length + j];
}
}
But What would be the code to convert a List < List < double > > to flatten array?
Is it possible to do it in 2 loops as the above code?
the List<List<double>> represents a double[,] arr
Honestly I'm not 100% sure what you're asking, but to flatten a List<List<>> you can use SelectMany from Linq, here's a simple example:
static void Main(string[] args)
{
var first = new List<double> {1, 2, 3};
var second = new List<double> { 3, 4, 5 };
var lists = new List<List<double>> {first, second};
var flatten = lists.SelectMany(a => a).ToArray();
foreach (var i in flatten)
{
Console.WriteLine(i);
}
}
Given the fact that your list ist a nested enumerable you can simply use Linq.
double[] array = nestedList.SelectMany(a => a).ToArray();
In a loop (i.e. without LINQ) would be something like
public static void Main()
{
List<List<double>> listOfLists = new List<List<double>>();
listOfLists.Add(new List<double>() { 1, 2, 3 });
listOfLists.Add(new List<double>() { 4, 6 });
int flatLength = 0;
foreach (List<double> list in listOfLists)
flatLength += list.Count;
double[] flattened = new double[flatLength];
int iFlat = 0;
foreach (List<double> list in listOfLists)
foreach (double d in list)
flattened[iFlat++] = d;
foreach (double d in flattened)
Console.Write("{0} ", d);
Console.ReadLine();
}

C# Multi-dimensional Array

I'm trying to build a multi-dimensional array to store integer arrays.
Array[] TestArray = new Array[2];
for(int i = 0; i < TestArray.Length; i++)
{
TestArray[i] = new int[5];
}
How do I go about accessing the newly created members of the Array? I am not sure how to access the newly created arrays in the array although I can see that they're properly created and stored when debugging in Visual Studio.
If you want an array of integer arrays, then you should declare it as such:
int[][] testArray = new int[2][];
for(int i = 0; i < testArray.Length; i++)
{
testArray[i] = new int[5];
}
Arrays of arrays are called Jagged Arrays (in contrast to Multidimensional Arrays).
Here is how to access fourth item in the second array:
int value = ((int[]) TestArray.GetValue(1))[3];
Although you would have much less trouble working with jagged arrays:
int[][] TestArray = new int[2][];
for (int i = 0; i < TestArray.Length; i++)
{
TestArray[i] = new int[5];
}
or multidimensional arrays:
int[,] TestArray = new int[2,5];
Cast the TestArray element as an int[].
Array[] TestArray = new Array[2];
for(int i = 0; i < TestArray.Length; i++)
{
TestArray[i] = new [] { 2,3 };
}
var firstIndexOfFirstArray = ((int[])TestArray[0])[0];
T[][] is the syntax you are looking for.
int[][] test = new int[2][]; //Declaring the array of arrays.
for (int i = 0; i < test.Length; i++)
{
test[i] = new int[5]; //Instantiating a sub-arrays.
for (int x = 0; x < test[i].Length; x++)
test[i][x] = x + i; //Filling a sub-arrays.
}
foreach (var array in test) //iterating over the array of arrays.
Console.WriteLine("Array: " + string.Join(", ", array)); //using a sub-array
Console.ReadLine();
For more info: http://msdn.microsoft.com/en-us/library/2s05feca.aspx
If looking for integer array, try
int[][] testArray

How to Sort 2D Array in C#

I've read lots of posts about sorting a 2D array but I still can't master it so I was wondering if anyone can offer me some advice...
I have an aray which lists letters and quantity (I'm doing a frequency anaysis on a piece of text). I've read this data into a rectangle array and need to order it by highest frequency first. Here's my code so far:
//create 2D array to contain ascii code and quantities
int[,] letterFrequency = new int[26, 2];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[(storeCount), (0)] = (char)(storeCount+66);
letterFrequency[(storeCount), (1)] = letterCount;
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
You are using a 2D array to represent 2 separate vectors - the symbols and the counts. Instead, use 2 separate arrays. Array.Sort has an overload that takes 2 arrays, and sorts on one array, but applies the changes to both, achieving what you want.
This would also allow you to use a char[] for the characters rather than int[]:
char[] symbols = ...
int[] counts = ...
...load the data...
Array.Sort(counts, symbols);
// all done!
At this
point, the counts have been ordered, and the symbols will still match index-by-index with the count they relate to.
You can wrap letter-count pair in a struct and use linq methods to manipulate data:
struct LetterCount {
public char Letter { get; set; }
public int Count { get; set; }
}
Sorting by count will look like this:
List<LetterCount> counts = new List<LetterCount>();
//filling the counts
counts = counts.OrderBy(lc => lc.Count).ToList();
public static void Sort2DArray<T>(T[,] matrix)
{
var numb = new T[matrix.GetLength(0) * matrix.GetLength(1)];
int i = 0;
foreach (var n in matrix)
{
numb[i] = n;
i++;
}
Array.Sort(numb);
int k = 0;
for (i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = numb[k];
k++;
}
}
}
Alternative approach:
var counts = new Dictionary<char,int>();
foreach(char c in text) {
int count;
counts.TryGetValue(c, out count);
counts[c] = count + 1;
}
var sorted = counts.OrderByDescending(kvp => kvp.Value).ToArray();
foreach(var pair in sorted) {
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
(untested)
In this case I'd choose to make use of KeyValuePair<TKey, TValue> and instead use something like this:
//create 2D array to contain ascii code and quantities
KeyValuePair<char, int>[] letterFrequency = new KeyValuePair<char, int>[26];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[storeCount] = new KeyValuePair<char, int>((char)(storeCount+66), letterCount);
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
Then use Array.Sort:
Array.Sort(letterFrequency, (i1, i2) => i2.Value.CompareTo(i1.Value));
This'll sort a two dimension array, the bool specifies if it's sorted on the second dimension, but default it sorts on the first dimension.
void SortDoubleDimension<T>(T[,] array, bool bySecond = false)
{
int length = array.GetLength(0);
T[] dim1 = new T[length];
T[] dim2 = new T[length];
for (int i = 0; i < length; i++)
{
dim1[i] = array[i, 0];
dim2[i] = array[i, 1];
}
if (bySecond) Array.Sort(dim2, dim1);
else Array.Sort(dim1, dim2);
for (int i = 0; i < length; i++)
{
array[i, 0] = dim1[i];
array[i, 1] = dim2[i];
}
}
Why are you storing the character? You can infer it from the array index and do not need to store it! Use a one-dimensional array instead.
string encryptedText = "Test".ToUpper();
int[] frequency = new int[26];
foreach (char ch in encryptedText) {
int charCode = ch - 'A';
frequency[charCode]++;
}
var query = frequency
.Select((count, index) => new { Letter = (char)(index + 'A'), Count = count })
.Where(f => f.Count != 0)
.OrderByDescending(f => f.Count)
.ThenBy(f => f.Letter);
foreach (var f in query) {
Console.WriteLine("Frequency of {0} is {1}", f.Letter, f.Count);
}

Categories

Resources