Initializing multidimensional arrays in c# (with other arrays) - c#

In C#, it's possible to initialize a multidimensional array using constants like so:
Object[,] twodArray = new Object[,] { {"00", "01", "02"},
{"10", "11", "12"},
{"20", "21", "22"} };
I personally think initializing an array with hard coded constants is kind of useless for anything other than test exercises. Anyways, what I desperately need to do is initialize a new multidimensional array as above using existing arrays. (Which have the same item count, but contents are of course only defined at runtime).
A sample of what I would like to do is.
Object[] first = new Object[] {"00", "01", "02"};
Object[] second = new Object[] {"10", "11", "12"};
Object[] third = new Object[] {"20", "21", "22"};
Object[,] twodArray = new Object[,] { first, second, third };
Unfortunately, this doesn't compile as valid code. Funny enough, when I tried
Object[,] twodArray = new Object[,] { {first}, {second}, {third} };
The code did compile and run, however the result was not as desired - a 3 by 3 array of Objects, what came out was a 3 by 1 array of arrays, each of which had 3 elements. When that happens, I can't access my array using:
Object val = twodArray[3,3];
I have to go:
Object val = twodArray[3,1][3];
Which obviously isn't the desired result.
So, is there any way to initialize this new 2D array from multiple existing arrays without resorting to iteration?

This would work if you switched to jagged arrays:
int[] arr1 = new[] { 1, 2, 3 };
int[] arr2 = new[] { 4, 5, 6 };
int[] arr3 = new[] { 7, 8, 9 };
int[][] jagged = new[] { arr1, arr2, arr3 };
int six = jagged[1][2];
Edit To clarify for people finding this thread in the future
The code sample above is also inadequate as it results in an array of arrays (object[object[]]) rather than a jagged array (object[][]) which are conceptually the same thing but distinct types.

You are trying to assign array references to an array. For more details please read - Jagged Arrays.
Try this,
Object[] first = new Object[] { "00", "01", "02" };
Object[] second = new Object[] { "10", "11", "12" };
Object[] third = new Object[] { "20", "21", "22" };
Object[][] result = { first, second, third };
foreach (object [] ar in result)
{
foreach (object ele in ar)
{
Console.Write(" " + ele);
}
Console.WriteLine();
}

I'm struggling to fully understand what you're really trying to achieve. If I got it right, you have some "lists" of strings, which you need to store in another list.
First of all, I'd recommend you to use a more modern approach than arrays. C# offers you IEnumerable<> and IList<> interfaces and all the stuff that derives from them, so no need to stick with old fashioned arrays.
You could do something like this:
var list1 = new List<string> { "foo1", "foo2", "foo3" };
var list2 = new List<string> { "foo4", "foo5", "foo6" };
var list3 = new List<string> { "foo7", "foo8", "foo9" };
var listOfStrings = new List<List<string>> { list1, list2, list3 };
Then if you want to access "foo6" you write:
var temp = listOfStrings[1][2];

The following works just fine:
var a = new object[] { 0, 1, 1, 2 };
var b = new object[] { "0", "5", "0", "0" };
var c = new object[] { true, true, true, false };
object[][] m = new object[][] { a, b, c };
var two = m[0][3];
var bar = m[1][1];
var f = m[2][3];

Related

Group array of string arrays with LINQ

I have array like this, values are string:
var arr1 = new [] { "H", "item1", "item2" };
var arr2 = new [] { "T", "thing1", "thing2" };
var arr3 = new [] { "T", "thing1", "thing2" };
var arr4 = new [] { "END", "something" };
var arr5 = new [] { "H", "item1", "item2" };
var arr6 = new [] { "T", "thing1", "thing2" };
var arr7 = new [] { "T", "thing1", "thing2" };
var arr8 = new [] { "END", "something" };
var allArrays = new [] { arr1, arr2, arr3, arr4, arr5, arr6, arr7, arr8 };
I need to group this in to a new array of arrays, so that one array has arrays that start with H or T. The END records (not included in the results) are the delimiters between each section; each new array starts after an END array.
In the end I would like to have somethng like this:
[
[ [H, item1, item2], [T, thing1, thing2], [T, thing1, thing2] ]
[ [H, item1, item2], [T, thing1, thing2], [T, thing1, thing2] ]
]
I know how I can do this with for each loop, but I'm looking for a cleaner way, possibly using linq. All suggestions are much valued, thank you!
you can try this
List<string[]> list = new List<string[]>();
var newArr = allArrays.Select(a => AddToArr(list, a)).Where(a => a != null);
and helper (this code can be put inline, but it easier to read this way)
private static string[][] AddToArr(List<string[]> list, string[] arr)
{
if (arr[0] != "END")
{
list.Add(arr);
return null;
}
var r = list.ToArray();
list.Clear();
return r;
}
result
[
[["H","item1","item2"],["T","thing1","thing2"],["T","thing1","thing2"]],
[["H","item3","item4"],["T","thing3","thing4"],["T","thing5","thing6"]]
]
So arr1, arr2, etc are string[].
allArrays is a string[][].
I hope you gave a meaningful example. From this example it seems that you want all string[] from allArrays, except the string[] that have a [0] that equals the word "END".
If this is what you want, your result is:
string[][] result = allArrays.Where(stringArray => stringArray[0] != "END");
I need to group this in to a new array of arrays, so that one array has arrays that start with H or T. The END records (not included in the results) are the delimiters between each section; each new array starts after an END array.
This is not exactly the same as I see in your example: what if one of the string arrays in allArrays is an empty array, or if it has the value null values. What if one of the the arrays of strings is empty (= length 0), and what if one of the string arrays doesn't start with "H", nor "T", nor "END"?
Literally you say that you only want the string arrays that start with "H" or "T", no other ones. You don't want string arrays that are null, nor empty string arrays. You also don't want string arrays that start with "END", nor the ones that start with String.Empty, or "A" or "B" or anything else than "H" or "T".
If I take your requirement literally, your code should be:
string[] requiredStringAtIndex0 = new string[] {"H", "T"};
string[][] result = allArrays.Where(stringArray => stringArray != null
&& stringArray.Length != 0
&& requiredStringAtIndex0.Contains(stringArray[0]));
In words: from allArrays, keep only those arrays of strings, that are not null, AND that have at least one element AND where the element at index 0 contains either "H" or "T"
Normally I would use an extension method for grouping runs of items based on a predicate, in this case GroupByEndingWith and then throw away the "END" record, like so:
var ans = allArrays.GroupByEndingWith(r => r[0] == "END")
.Select(g => g.Drop(1).ToArray())
.ToArray();
But, in general, you can use Aggregate to collect items based on a predicate at the expense of comprehension. It often helps to use a tuple to track an overall accumulator and a sub-accumulator. Unfortunately, there is no + operator or Append for List<T> that returns the original list (helpful for expression based accumulation) and since C# doesn't yet have a comma operator equivalent, you need an extension method again or you can use ImmutableList.
Using Aggregate and ImmutableList, you can do:
var ans = allArrays.Aggregate(
(ans: ImmutableList<ImmutableList<string[]>>.Empty, curr: ImmutableList<string[]>.Empty),
(ac, r) => r[0] == "END"
? (ac.ans.Add(ac.curr), ImmutableList<string[]>.Empty)
: (ac.ans, ac.curr.Add(r))
).ans
.Select(l => l.ToArray())
.ToArray();
NOTE: You can also do this with List if you are willing to create new Lists a lot:
var ans = allArrays.Aggregate(
(ans: new List<List<string[]>>(), curr: new List<string[]>()),
(ac, r) => r[0] == "END"
? (ac.ans.Concat(new[] { ac.curr }).ToList(), new List<string[]>())
: (ac.ans, ac.curr.Concat(new[] { r }).ToList())
).ans
.Select(l => l.ToArray())
.ToArray();
Here is a simple implementation.
public static void Main(string[] args)
{
var data = ConvertToArrayOfArray(arr1, arr2, arr3, arrr4, arr5, arr6, arr7, arr8);
}
private string[][] ConvertToArrayOfArray(params string[][] arrs)
{
List<string[]> yoList = new List<string[]>();
arrs.ToList().ForEach(x =>
{
if(!x[0] == "END") yoList.Add(x);
});
return yoList.ToArray();
}

Array of multiple types C# (including other arrays)

Is there a way to have an array of multiple types in c#, including other arrays?
Apparently I can do this:
object[] x = {1,"G",2.3, 2,'H'};
but not this:
object[] x = {1,"G",2.3, 2,'H', {2} };
What's the proper way to do it?
Problem is that that you cannot initialize the inner array this way. The array initalizer can only be used in a variable or field initializer. As your error states:
Array initializer can only be used in a variable or field initializer. Try using a new expression insead
You must explicitly initialize the nested arrays. Do it this way and it works:
object[] x = { 1, "G", 2.3, 2, 'H', new int[]{ 2 } };
// Or a bit cleaner
object[] x = { 1, "G", 2.3, 2, 'H', new []{ 2 } };
Read more on Array Initializers
Your syntax would work if you'd define a 2 dimensional array:
object[,] x = { {"3"}, { 1 }, { 2 } };
object[] x = {1,"G",2.3, 2,'H', {2} }; was wrong and u can use
object[] x = { 1, "G", 2.3, 2, 'H', new int[]{ 2 } };

Get the value of array using c# [duplicate]

This question already has answers here:
How do I remove duplicates from a C# array?
(28 answers)
Closed 7 years ago.
I got an array
string [] strings = new string[] {"1", "2", "2", "2", "1"};
You can see the value of the array is just 1 and 2, just 2 values, you could say, and I want to get those value out...What I did is here, just a start:
string[] strings = new[] { "1", "2", "2", "2", "1"};
int[] ints = strings.Select(x => int.Parse(x)).ToArray();
I don't what is next...Anyone helps?
You mean you just want an array int[] {1, 2}?
string[] strings = new[] { "1", "2", "2", "2", "1"};
int[] ints = strings.Select(int.Parse).Distinct().ToArray();
You may simply add a distinct to get the unique values:
int[] ints = strings.Select(x => int.Parse(x)).Distinct().ToArray();
Thus your array contains the elements {1, 2}
Classic way:
string[] strings = new[] { "1", "2", "2", "2", "1" };
List<int> items = new List<int>();
for (int i = 0; i < strings.Length; i++)
{
int item = int.Parse(strings[i]);
if (!items.Contains(item))
items.Add(item);
}

Extracting 'single item' from Multi Dimensional Array (c#)

Say I have the code
var marray = new int[,]{{0,1},{2,3},{4,5}};
Is it possible to get a reference to the first item - i.e. something that looked like:
var _marray = marray[0];
//would look like: var _marray = new int[,]{{0,1}};
Instead, when referencing marray from a one dimensional context, it sees marray as having length of 6
(i.e. new int[]{0,1,2,3,4,5})
Use a jagged array
var marray = new[] { new[] { 0, 1 }, new[] { 2, 3 }, new[] { 4, 5 } };
Console.WriteLine(marray[0][1]);

Combine arrays by element into jagged array

I have a method which accept jagged array of Objects.
public void MyDataBind(object[][] data)
I use it like this
GoogleChart1.MyDataBind(new[] { new object[] { "September 1", 1 }, new object[] { "September 2", 10 } });
I have source data in two arrays like these and want to pass them to the method:
var sDate = new string[] {"September 1", "September 2"};
var iCount = new int[] { 1, 2 };
How can I pass, cast or transform these predefined array values to this method?
If you're using .NET 4 then the Zip method could be used to merge the two arrays:
MyDataBind(sDate.Zip(iCount, (s, i) => new object[] { s, i }).ToArray());
EDIT:
even simpler and cleaner:
var result = sDate.Select((s, index) => new object[] { s, iCount[index] }).ToArray();
A simple solution:
List<object> items = new List<object>();
for (int i = 0; i < sDate.Length; i++)
items.Add(new object[] { sDate[i], iCount[i] });
var result = items.ToArray();
You can define a method Combine(T[] array1, T[] array2) so get a more generic solution.

Categories