Take slice from 2D array (int[ , ]) using LINQ in C# - c#

I am not C# expert, and total LINQ beginner, having searched a bit in SO and Google without discovering how to do the following:
If I have, say, int[10,10] array, how can I get a 2D slice from it?
For example, if the values in the said array were dependent on their position (a[2,3] = 23, a[4,8] = 48, etc.), I'd like to perform the following pseudocode:
int[3,3] a_slice = slicer_method(a, 3, 6, 2, 5) // or anything equivalent to this
> [[ 32, 33, 34],
[ 42, 43, 44],
[ 52, 53, 54]]
It doesn't have specifically to use LINQ, but I've seen LINQ used in every similar operation I've come across lately.

#JaredPar is correct, there is no intrinsic way to do slices - that said, you can craft up an extension method to do so:
public static class Ext
{
public static T[] Slice<T>(this T[] source, int fromIdx, int toIdx)
{
T[] ret = new T[toIdx - fromIdx + 1];
for(int srcIdx=fromIdx, dstIdx = 0; srcIdx <= toIdx; srcIdx++)
{
ret[dstIdx++] = source[srcIdx];
}
return ret;
}
public static T[,] Slice<T>(this T[,] source, int fromIdxRank0, int toIdxRank0, int fromIdxRank1, int toIdxRank1)
{
T[,] ret = new T[toIdxRank0 - fromIdxRank0 + 1, toIdxRank1 - fromIdxRank1 + 1];
for(int srcIdxRank0=fromIdxRank0, dstIdxRank0 = 0; srcIdxRank0 <= toIdxRank0; srcIdxRank0++, dstIdxRank0++)
{
for(int srcIdxRank1=fromIdxRank1, dstIdxRank1 = 0; srcIdxRank1 <= toIdxRank1; srcIdxRank1++, dstIdxRank1++)
{
ret[dstIdxRank0, dstIdxRank1] = source[srcIdxRank0, srcIdxRank1];
}
}
return ret;
}
}
And a test:
void Main()
{
var singleArr = new int[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
singleArr.Slice(2, 4).Dump();
var doubleArr = new int[,]
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
};
doubleArr.Slice(2, 4, 2, 4).Dump();
}

There is no way to do this on the CLR because it doesn't support the notion of array slices. They best you can do is create a wrapper type over arrays that simulates slices

You can try something like this:
public T[,] Slice<T>(T[,] a, int x1, int y1, int x2, int y2)
{
var result = new T[x2 - x1, y2 - y1];
for (var i = x1; i < x2; i++)
{
for (var j = y1; j < y2; j++)
{
result[i - x1, j - y1] = a[i,j];
}
}
return result;
}
sample

public class MyArraySlice<T> where T:struct {
public MyArraySlice(T[,] array, int xMin, int xMax, int yMin, int yMax) {
Array = array;
XMin = xMin; XMax = xMax;
YMin = yMin; YMax = yMax;
}
public T this[int i, int j] { get {
if (XMin <= i && i < XMax && YMin <= j && j < YMax)
return Array[i+XMin, j+YMin];
throw new ArgumentOutOfRangeException();
}
}
T[,] Array;
int XMin;
int XMax;
int YMin;
int YMax;
}

Related

How to implement a multidimensional array shuffling in CSharp?

I wonder if it is possible to implement a general Julia\Matlab alike View function in C# that would work for arrays of any dimensions (eg [,,] and [,,,]) as they do it in array slicer\mover view. So I wonder if there is a library that provides similar functionality for CSharp multidimentional arrays or how to implement it in C#?
The solution is twofold:
Use a wrapper class that holds a reference to the master array
Use the Array base class to make it polymorphic
Wrapper
class View<T>
{
private readonly Array array;
private readonly int dim;
private readonly int slice;
public View(Array array, int dim, int slice)
{
this.array = array;
this.dim = dim;
this.slice = slice;
}
public T this[params int[] indexes]
{
get { return (T)array.GetValue(BaseIndexesFor(indexes)); }
set { array.SetValue(value, BaseIndexesFor(indexes)); }
}
private int[] BaseIndexesFor(int[] indexes)
{
if (indexes.Length != array.Rank - 1) throw new ArgumentException("indexes");
int i_index = 0;
int[] baseIndexes = new int[array.Rank];
for (int i = 0; i < baseIndexes.Length; i++)
{
baseIndexes[i] = (i == dim) ? slice : indexes[i_index++];
}
return baseIndexes;
}
}
2D example
var A = new int[,]
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
/* View(Array array, int dim, int slice)
*
* For 2 dimensional array:
* dim=0 -> rows
* dim=1 -> columns
*/
// From second dimension slice index 1
// Or simply, take column with index 1
var B = new View<int>(A, 1, 1);
B[2] = 0;
Console.WriteLine(A[2, 1]); // 0
3D examples
var C = new int[,,]
{
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
},
{
{ 11, 12, 13 },
{ 14, 15, 16 },
{ 17, 18, 19 }
},
{
{ 21, 22, 23 },
{ 24, 25, 26 },
{ 27, 28, 29 }
}
};
/* From first dimension slice index 2
* { 21, 22, 23 },
* { 24, 25, 26 },
* { 27, 28, 29 }
*/
var D = new View<int>(C, 0, 2);
D[1, 1] = 0;
Console.WriteLine(C[2, 1, 1]); // 0
/* From third dimension slice index 0
* { 1, 4, 7 },
* { 11, 14, 17 },
* { 21, 24, 27 }
*/
var E = new View<int>(C, 2, 0);
E[2, 0] = 0;
Console.WriteLine(C[2, 0, 0]); // 0

How can I separate a multi-dimension (2D) array by rows into multiple 1D arrays?

I am programming in C# and I currently have the 2D array below:
int[,] results = {
{ 4, 7, 9, 3, 8, 6, 4},
{ 4, 8, 6, 4, 8, 5, 6},
{ 7, 3, 9, 2, 2, 1, 8}
};
I'd like to create a loop or function which outputs 3 separate arrays, copying the values from each row.
e.g. output:
row1 = {4, 7, 9, 3, 8, 6, 4}
row2 = {4, 8, 6, 4, 8, 5, 6}
etc
I have been able to copy the values of each row into a separate string which is then written in the console with this line of code:
for (int a = 1; a < (rows+1); a++)
{
for (int b = 1; b < (columns+1); b++)
{
scores = scores + " " + results[(a-1), (b-1)];
}
scores = "";
}
you need a convertion from a 2D array into a jagged array
int[,] array = { { 4, 7, 9, 3, 8, 6, 4},
{ 4, 8, 6, 4, 8, 5, 6},
{ 7, 3, 9, 2, 2, 1, 8}
};
int[][] jagged = new int[array.GetLength(0)][];
for (int i = 0; i < array.GetLength(0); i++)
{
int[] row = new int[array.GetLength(1)];
for (int j = 0; j < array.GetLength(1); j++)
{
row[j] = array[i, j];
}
jagged[i] = row;
}
int[] row1 = jagged[0];
int[] row2 = jagged[1];
int[] row3 = jagged[2];
difference between multidimensional array and jagged array:
//multidimensional array
int[,] multi = { { 7, 2, 6, 1 }, { 3, 5, 4, 8 } };
//array of arrays (jagged array)
int[][] jagged = new int[][] { new int[] { 7, 2, 6, 1 }, new int[] { 3, 5, 4, 8 } };
LINQ variant:
var m0 = new int[,] { { 1, 2 }, { 3, 4 } };
var rows = Enumerable.Range(0, m0.GetLength(0)).Select(i => Enumerable.Range(0, m0.GetLength(1)).Select(j => m0[i, j]));
foreach (var r in rows) Console.WriteLine(string.Join(" ", r));
Console.ReadLine();
a 'smarter' variant (flattern an array and take by N values):
var rows = m0.Cast<int>().Select((v, i) => new { i = i / m0.GetLength(1), v }).GroupBy(e => e.i).Select(g => g.Select(e => e.v));
Just a piece of cake using JsonSoft as
var json = JsonConvert.SerializeObject(results);
int[][] arr = JsonConvert.DeserializeObject<int[][]>(json);
int[] arr1 = arr[0];
int[] arr2 = arr[1];
int[] arr3 = arr[2];

Fastest algorithm to merge 2 arrays such that elements are interlocked at even intervals

Requirements:
Integer operations only (no floats)
Elements are interlocked at intervals as evenly as possible
Note:
"Intervals as evenly as possible" can be defined as having each length of intervals as close to one value as possible.
Micro-optimizations are welcome and desired.
Example inputs and outputs:
//Inputs
[ 1, 2, 3, 4, 5, 6, 7 ]
[ 10, 20, 30, 40 ]
//Correct output
[ 1, 10, 2, 20, 3, 30, 4, 5, 40, 6, 7]
//Wrong output ([5, 6, 7] is not an optimal interval)
[ 1, 10, 2, 20, 3, 30, 4, 40, 5, 6, 7]
-
//Inputs
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[ 2, 2, 2 ]
//Correct output
[ 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 3, 1, 1]
//Wrong output (last [1] is not an optimal interval)
[ 1, 1, 1, 3, 1, 1, 1, 3, 1, 1, 1, 3, 1]
Here's my own implementation with as much optimization as I can think of for a managed language. In C++, it may be faster to use a triple XOR swap for the array pointers, but I'm not sure. It may be necessary to look at the JITed assembly to further optimize this particular code.
In the meantime, let's see if other people have better algorithms.
int[] InterlockMerge(int[] a1, int[] a2) {
var longSet = a1;
var shortSet = a2;
//Swap if a2 is longer
if (a1.Length < a2.Length){
longSet = a2;
shortSet = a1;
}
var ll = longSet.Length;
var ls = shortSet.Length;
var totalLength = ll + ls;
int[] res = new int[totalLength]; //The resulting set
int l = ll / (ls + 1); //Initial testing ratio (an int)
int li = 0; //index for longSet
int si = 0; //index for shortSet
for (int i = 0; i < totalLength; i++) {
if (l > 0) {
res[i] = longSet[li++];
l--;
continue;
}
res[i] = shortSet[si++];
l = (ll - li) / (ls - si + 1); //Recalculate the testing ratio
}
return res;
}

Randomly pick from a list of numbers until specific limit

Let's say I have a list of predefined numbers, and a list of predefined max limits.
When a user picks a limit, I need to randomly pick a certain amount of numbers from the first list, up until their totals match (As close to, but never over) the user selected total.
What I've tried so far:
void Main()
{
List<int> num = new List<int>(){ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20 };
int maxNum = 17;
List<int> curNum = new List<int>();
int curTotal = 0;
foreach(int sel in num.Where(x => x < maxNum)){
curTotal += sel;
if(curTotal <= maxNum){
curNum.Add(sel);
}
}
}
There needs to be x amount of numbers picked. In this case, 5 numbers picked, +- 20 numbers to be randomly picked from, and 1 max values.
So the end list should look like this:
1, 2, 3, 4, 7 (17)
1, 2, 3, 5, 6 (17)
1, 2, 3, 4, 6 (16) <- This will be fine if there isn't a solution to the max value.
Building upon #AlexiLevenkov's answer:
class Program
{
static void Main(string[] args)
{
int limit = 17;
int listSize = 5;
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
a.Shuffle();
List<int> genList = new List<int>();
int stoppedCount = 0;
for (int i = 0; i < a.Count(); i++)
{
if (i < listSize)
{
genList.Add(a[i]);
stoppedCount = i;
}
else
{
break;
}
}
while (genList.Sum() > limit)
{
genList.Remove(genList.Max());
stoppedCount++;
genList.Add(a[stoppedCount]);
}
}
}
static class ThisClass
{
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
I think shuffle + "take while sum < limit" may be what you are looking for.
Something like following:
var shuffledList = num.ToList();
shuffledList.Shuffle();
var sum = 0;
var count = 0;
while (shuffledList[count] + sum < max)
{
sum += shuffledList[count++];
}
return shuffledList.Take(count);

How to fill a three dimensional array

I want to fill a three dimensional array with the following arrays:
double[] y11 = new double[7] { 24, 13.3, 12.2, 14, 22.2, 16.1, 27.9 };
double[] y12 = new double[7] { 3.5, 3.5, 4, 4, 3.6, 4.3, 5.2 };
double[] y21 = new double[7] { 7.4, 13.2, 8.5, 10.1, 9.3, 8.5, 4.3 };
double[] y22 = new double[7] { 3.5, 3, 3, 3, 2, 2.5, 1.5 };
double[] y31 = new double[5] { 16.4, 24, 53, 32.7, 42.8 };
double[] y32 = new double[5] { 3.2, 2.5, 1.5, 2.6, 2 };
double[] y41 = new double[2] { 25.1, 5.9 };
double[] y42 = new double[2] { 2.7, 2.3 };
for instance y12 means the array in group 1 , column number 2 and so on. so i have 4 groups ,each group has 2 columns.
public class Matrix
{
double[, ,] matrix;
public void Initial(int groupSize, int columnSize, int valueSize)
{
matrix = new double[groupSize, columnSize, valueSize];
}
}
I need a simple flexible Add method for the matrix, rather than assigning each value like matrix[1][2][3] = value;
I've tried this, but couldn't get it work
public void Add(double[] columnArray, int groupIndex, int columnIndex)
{
matrix[i, y] = columnArray;
}
According to #Henk Holterman 's Comment (thank you), I've managed to solve the problem
public class Matrix
{
double[,][] matrix;
public Matrix(int groupSize, int columnSize)
{
matrix = new double[groupSize, columnSize][];
}
public void Add(double[] arr, int groupIndex, int columnIndex)
{
matrix[groupIndex, columnIndex] = arr;
}
public void Print()
{
int columnIndex = 0;
int groupIndex = 0;
int groupSize = matrix.GetLength(0);
int columnSize = matrix.GetLength(1);
while (groupIndex < groupSize)
{
for (int k = 0; k < matrix[groupIndex, columnIndex].Length; k++)
{
Console.Write(groupIndex + 1);
while (columnIndex < columnSize)
{
Console.Write(" {0}", matrix[groupIndex, columnIndex][k]);
columnIndex++;
}
Console.WriteLine();
columnIndex = 0;
}
groupIndex++;
}
}
}
Main Class
static Matrix m;
static void SetDataSet()
{
double[] y11 = new double[7] { 24, 13.3, 12.2, 14, 22.2, 16.1, 27.9 };
double[] y12 = new double[7] { 3.5, 3.5, 4, 4, 3.6, 4.3, 5.2 };
double[] y21 = new double[7] { 7.4, 13.2, 8.5, 10.1, 9.3, 8.5, 4.3 };
double[] y22 = new double[7] { 3.5, 3, 3, 3, 2, 2.5, 1.5 };
double[] y31 = new double[5] { 16.4, 24, 53, 32.7, 42.8 };
double[] y32 = new double[5] { 3.2, 2.5, 1.5, 2.6, 2 };
double[] y41 = new double[2] { 25.1, 5.9 };
double[] y42 = new double[2] { 2.7, 2.3 };
m.Add(y11, 0, 0);
m.Add(y12, 0, 1);
m.Add(y21, 1, 0);
m.Add(y22, 1, 1);
m.Add(y31, 2, 0);
m.Add(y32, 2, 1);
m.Add(y41, 3, 0);
m.Add(y42, 3, 1);
}
static void Main(string[] args)
{
m = new Matrix(4,2);
SetDataSet();
m.Print();
Console.ReadLine();
}
}

Categories

Resources