2D Array. Set all values to specific value - c#

To assign specific value to 1D array I'm using LINQ like so:
int[] nums = new int[20];
nums = (from i in nums select 1).ToArray<int>();
nums[0] = 2;
There is similar way to do so in 2D ([x,y]) array?
Or short way, without using nested loops?

If you really want to avoid nested loops you can use just one loop:
int[,] nums = new int[x,y];
for (int i=0;i<x*y;i++) nums[i%x,i/x]=n;
You can make it easier by throwing it into some function in a utility class:
public static T[,] GetNew2DArray<T>(int x, int y, T initialValue)
{
T[,] nums = new T[x, y];
for (int i = 0; i < x * y; i++) nums[i % x, i / x] = initialValue;
return nums;
}
And use it like this:
int[,] nums = GetNew2DArray(5, 20, 1);

LINQ doesn't work particularly well with multi-dimensional arrays.
Jagged arrays aren't too bad:
var array = Enumerable.Range(0, 10)
.Select(x => Enumerable.Repeat('x', 10).ToArray())
.ToArray();
... but rectangular arrays don't have any specific support. Just use loops.
(Note the use of Enumerable.Repeat as a somewhat simpler approach to creating the 1-dimensional array, btw.)

Well, this might be cheating because it simply moves the looping code to an extension method, but it does allow you to initialize your 2D array to a single value simply, and in a fashion similar to how you can initialize a 1D array to a single value.
First, as Jon Skeet mentioned, you could clean up your example of initializing a 1D array like this:
int [] numbers = Enumerable.Repeat(1,20).ToArray();
With my extension method, you will be able to initialize a 2D array like this:
public static T[,] To2DArray<T>(this IEnumerable<T> items, int rows, int columns)
{
var matrix = new T[rows, columns];
int row = 0;
int column = 0;
foreach (T item in items)
{
matrix[row, column] = item;
++column;
if (column == columns)
{
++row;
column = 0;
}
}
return matrix;
}

One way you could do this is like so:
// Define a little function that just returns an IEnumerable with the given value
static IEnumerable<int> Fill(int value)
{
while (true) yield return value;
}
// Start with a 1 dimensional array and then for each element create a new array 10 long with the value of 2 in
var ar = new int[20].Select(a => Fill(2).Take(10).ToArray()).ToArray();

May I suggest a new extension method.
public static class TwoDArrayExtensions
{
public static void ClearTo(this int[,] a, int val)
{
for (int i=a.GetLowerBound(0); i <= a.GetUpperBound(0); i++)
{
for (int j=a.GetLowerBound(1); j <= a.GetUpperBound(1); j++)
{
a[i,j] = val;
}
}
}
}
Use it like this:
var nums = new int[10, 10];
nums.ClearTo(1);

You can create a simple method that loops over all elements and initializes them:
public static void Fill2DArray<T>(T[,] arr, T value)
{
int numRows = arr.GetLength(0);
int numCols = arr.GetLength(1);
for (int i = 0; i < numRows; ++i)
{
for (int j = 0; j < numCols; ++j)
{
arr[i, j] = value;
}
}
}
This uses the same syntax as Array.Fill and will work for an array of any type

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;
}

How to copy one-dimensional array into two-dimensional [duplicate]

This question already has answers here:
Copy single row from multidimensional array into new one dimensional array
(3 answers)
Closed 1 year ago.
Having the following:
int[,] a = new int[4, 2];
int[] b = new int[2];
how do I copy values from b into the first element of a? What's wrong with b.CopyTo(a[0])?
You can access a only by using 2 coordinates (so a[x,y]) because it is defined using 2 dimensions.
Try using int[][] a instead, if you do that then a becomes an array containing 1-dimensional subarrays, and then you can use 1 coordinate to access a subarray.
Example code:
int[][] a = new int[4][];
a[0] = new int[2];
int[] b = new int[2];
Note that after this, when I try do to b.CopyTo(a[0]) I get a "The call is ambiguous " compilation error (in .NET 5) because there two different extension methods that both match the CopyTo signature...
What's wrong with b.CopyTo(a[0])?
A is a two dimensional array, so you need two indices, i.e. a[0,0] = b[0]
Instead of using the built in multidimensional array I would suggest using a wrapper around a 1D array instead, with a indexer something like this:
public T this[int x, int y]
{
get => Data[y * Width + x];
set => Data[y * Width + x] = value;
}
This has the advantage of easier interoperability, since many system exposes 2D buffers of various kinds as 1D data + size. This allows copying data to be done by a block copy instead of copying element by element.
For primitives array types you can define extension methods for packing or unpacking arrays using the Buffer.BlockCopy();
static class Program
{
static void Main(string[] args)
{
int[,] A = new[,] { { 1, 2 }, { 3, 4 } };
int[] data = A.PackMarix();
int[,] B = data.UnPackMarix(2, 2);
Console.WriteLine(B);
}
public static int[,] UnPackMarix(this int[] data, int rows, int columns)
{
int[,] result = new int[rows, columns];
int bytes = Buffer.ByteLength(data);
Buffer.BlockCopy(data, 0, result, 0, bytes);
return result;
}
public static int[] PackMarix(this int[,] data)
{
int[] result = new int[data.Length];
int bytes = Buffer.ByteLength(data);
Buffer.BlockCopy(data, 0, result, 0, bytes);
return result;
}
}
For non-primitive types you have to do the copying manually
public static T[,] UnPackMarix<T>(this T[] data, int rows, int columns)
{
var result = new T[rows, columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
result[i, j] = data[i * columns + j];
}
}
return result;
}
public unsafe static T[] PackMarix<T>(this T[,] data)
{
var result = new T[data.Length];
int rows = data.GetLength(0);
int columns = data.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
result[i * columns + j] = data[i, j];
}
}
return result;
}
This has been posted on SO before but I couldn't find the old post. Anyway, use the Microsoft High Performance toolkit. It has spans for 2D memory. With that you can do this:
int[,] a = new int[4, 2];
int[] b = { 1, 2 };
var spanB = b.AsSpan();
var spanA = a.AsSpan2D();
spanB.CopyTo(spanA.GetRowSpan(0));
foreach (var i in spanA)
Console.WriteLine(i);

C# 2D Array calling it another class through obj.method();

Write a Java class that has a static method named count that accepts a 2D-Array of integers and a target integer value as parameters and returns the number of occurrences of the target value in the array. For example, if a variable named list refers to an array containing values {{3,5,7,94}{5,6,3,50}} then the call of count(list, 3) should return 2 because there are 2 occurrences of the value 3 in the array.
Here is my coding and it's not giving me proper output
P.S :-I have been told to take count method as public not static
class java
{
public int count(int [,] list,int n)
{
int c = 0;
for (int i = 0; i <list.Length; i++)
{
for (int j = 0; j < list.Length; j++)
{
if (list[i, j] == n)
{
c++;
}
}
}
return c;
}
class Program
{
static void Main(string[] args)
{
java jv = new java();
int[,] arr = { { 3, 5, 7, 94 }, {5, 6, 3, 50 } };
int k=0;
jv.count(arr,k);
}
}
Iterating Multi-Dimensional arrays requires you to iterate each dimension with it's own Length, which means i and j should be 0-3 and 0-1 respectively.
as can be seen in the picture but for a different dimensioned array:
GetLength(0) would return 4.
GetLength(1) would return 3.
What you are doing is iterating them when i = (0 to Length) over j = (0 to Length) when Length = Height * Width = 8 in your case which means 8 over 8.
So your count() method should look like that:
public int count(int[,] list,int n)
{
int c = 0;
for (int i = 0; i < list.GetLength(0); i++)
{
for (int j = 0; j < list.GetLength(1); j++)
{
if (list[i, j] == n)
{
c++;
}
}
}
return c;
}
if you would like to iterate the array as an array of arrays instead of getting things complicated with "Which dimension am I iterating now?" you can use Jagged Arrays (Of course there are more things to consider about it), this will allow you to replace the whole method with this one short Linq:
public int count(int[][] list,int n)
{
return list.SelectMany(x => x).Count(x => x == n);
}
or:
public int count(int[][] list, int n)
{
return list.Sum(x => x.Count(y => y == n));
}
Note the i against j in inner for.
And do use i <list.GetLength(0) and j < list.GetLength(1) against list.Length
class java
{
public int count(int [,] list,int n)
{
int c = 0;
for (int i = 0; i < list.GetLength(0); i++)
{
for (int j = 0; j < list.GetLength(1); j++)
{
if (list[i, j] == n)
{
c++;
}
}
}
return c;
}
class Program
{
static void Main(string[] args)
{
java jv = new java();
int[,] arr = { {3,5,7,94 }, {5,6,3,50 } };
int k=5;
Console.WriteLine(jv.count(arr,k));
}
}
Since Array has implemented IEnumerable you can simply use foreach loop here (feel free to change static to instance method) :
public static int count(int[,] list, int n)
{
int c = 0;
foreach (var item in list) if (item == n) c++;
return c;
}
Usage:
static void Main()
{
var r = count(new int[,]{
{
5, 8, 7, 8
},
{
0, 8, 9, 3
}}, 8);
Console.WriteLine(r);
output : 3
P.S.
Generally if possible, it is best to use a for loop as it is faster than foreach but in these case i like that if you use foreach you don't have nested for loops nor GetLength(x) calls it's just one line of code and it has almost same performance...
Your error is in this line:
for (int j = 0; i < list.Length; j++)
It should be
for (int j = 0; j < list.Length; j++)

Initialize multidimensional array of objects in c#

I was just wondering, is there a better way to initialize c# multidimensional array of objects (reference type).
Here is my code:
Board = new Field[BoardHeight, BoardWidth];
for (int i = 0; i < BoardHeight; i++)
{
for (int j = 0; j < BoardWidth; j++)
{
Board[i, j] = new Field();
}
}
If I could get rid of for/for loops and replace it with single line? That'd be just great.
Nested for loops is generally most readable/accepted approach to initialize 2d array.
If you really need single statement - one option is to use Enumerable.Aggregate (to create/fill array in single statement) and Enumerable.Range + Enumerable.SelectMany (to create indexes using How do I take the Cartesian join of two lists in c#?):
Board = Enumerable.Range(0, BoardHeight)
.SelectMany(x => Enumerable.Range(0, BoardWidth), (row,col)=>new {row,col})
.Aggregate(new Field[BoardHeight, BoardWidth],
(board, position)=>
{
board[position.row,position.col] = new Field();
return board;
});
(Readability of this code is open for discussion)
A bit more practical solution:
for (var i = 0; i < BoardHeight* BoardWidth; i++)
{
Board[i / BoardWidth, i % BoardWidth] = new Field();
}
If you really need "single line initialization" - refactor nested for loop into method (possibly generic) and call it wherever you want with "single line". Something like:
public TField[,] InitializeArray<TField>(
int BoardHeight, int BoardWidth) where TField:new()
{
var Board = new TField[BoardHeight, BoardWidth];
for (int i = 0; i < BoardHeight; i++)
{
for (int j = 0; j < BoardWidth; j++)
{
Board[i, j] = new TField();
}
}
return Board;
}
More for curiosity's sake than anything else, I adapted some old code into an extension method that will initialize every member of an array of arbitrary rank with the results of a provided Func. You'd use it like this (with 2D, 3D, whatever-D arrays):
var board = new Foo[10, 20];
board.Fill(() => new Foo());
Here's the extension method:
static class Extensions
{
public static void Fill(this Array arr, Func<object> gen)
{
// Get the dimensions of the array
var dims = Enumerable.Range(0, arr.Rank)
.Select(arr.GetLength)
.ToArray();
Func<int, int, int> product = (i1, i2) => i1 * i2;
for (var i = 0; i < arr.Length; i++)
{
var indices = dims.Select((d, n) => (i/dims.Take(n).Aggregate(1, product))%d).ToArray();
arr.SetValue(gen(), indices);
}
}
}
Thanks to MarcinJuraszek and Alexei Levenkov suggestions I came out with this answer. Technically is not a single statement (all in all), but if you hide extension method ;-) it will look very clean:
Board = new Field[BoardHeight, BoardWidth];
Board.Init();
Hide this somewhere:
public static class MyExtensions
{
public static void Init<T>(this T[,] board) where T : new()
{
for (int i = 0; i < board.GetLength(0); i++)
{
for (int j = 0; j < board.GetLength(1); j++)
{
board[i,j] = new T();
}
}
}
}
I think this is the easiest one-liner (split to multiple lines for readability) to initialize your array:
var board = Enumerable.Range(0, BoardWidth)
.Select(row => Enumerable.Range(0, BoardHeight)
.Select(value =>new TField())
.ToArray())
.ToArray();

Initializing two dimensional array of objects

I have a 2-dimensional array of objects, which I initialize using the traditional loop:
PairDS[,] tempPb1 = new PairDS[LoopCounterMaxValue+1, LoopCounterMaxValue+1];
for (int i = 0; i <= LoopCounterMaxValue; i++)
for (int j = 0; j <= LoopCounterMaxValue; j++)
tempPb1[i, j] = new PairDS();
Is there any better way to do this using Enumerable or something?
I thought Initialize could do it, but it only works with value types.
int N = 10;
PairDS[,] temp = new PairDS[N + 1, N + 1];
temp.Initialize();
What I recommend you do is use a jagged array.
class PairDS { public PairDS(int row, int col) { } }
static void Main(string[] args)
{
int N = 10;
PairDS[][] temp = Enumerable.Range(0, N + 1).Select(
(row) => Enumerable.Range(0, N + 1).Select(
(col) => new PairDS(row, col)).ToArray()).ToArray();
}
I don't believe you can represent a multi-dimensional array as an Enumerable or List, directly because it (the CLR) has no way of knowing how you intend to index the array.
If you did work it out row by row, it'd actually be worse (ie slower) then simply looping through the array as you're doing and initializing each cell.
There's no way to directly initialize a 2D array with the Enumerable types and as some users have pointed out there's nothing directly wrong with what you're doing. If you're just looking to simplify the loop though this might be what you're looking for;
const int length = LoopCounterMaxValue + 1;
PairDS[,] tempPb1 = new PairDS[length, lenth];
for (var i = 0; i < length * length; i++) {
var column = i % length;
var row = (i - column) / length;
tempPb1[row, column] = new PairDS();
}

Categories

Resources