Performant Concatenating 2D Arrays stored as sub-arrays [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
Imagine we got a couple of 3x3 2D arrays that are identified by a X Y coordinate.
Pseudo code:
Array 0-0 Array 1-0
[[1,2,1] [[1,2,1]
[2,3,2] [2,3,2]
[3,1,2]] [3,1,2]]
Array 0-1 Array 1-1
[[1,2,1] [[1,2,1]
[2,3,2] [2,3,2]
[3,1,2]] [3,1,2]]
And we also have an index array, to index all this sub-arrays.
chunk_array = [
[Array 0-0, Array 0-1],
[Array 1-0, Array 1,1]
]
The problem is how to quickly create a final array, 6x6 containing all sub-arrays without having to iterate all elements of the array as this is a very critical place that has to operate in the minimal time possible.
So question: What would be the quickest way to perform this operation ? I've looked at Buffer copy, but not sure still what would be the best approach here.

Here's a solution based on the suggestion of Alexei Levenkov in the comments. From his comment: Fastest way to do something is not to do it at all... Does that work in your case (i.e. by wrapping all 4 into a class that exposes indexing the way you like)?
You create your four individual arrays and then add them to a wrapper capable of holding those arrays in a rectangular array. I use a function to access the individual elements, but you could use an indexer instead (if you are inclined that way - I'm not, that accessor seems a bit too complex for a simple indexer).
Here's the main class:
public class CompositeArray<T> where T:new()
{
private readonly T[,][,] _componentArray = null;
public int IndividualArrayWidth { get; }
public int IndividualArrayHeight { get; }
public int ComponentArrayWidth { get; }
public int ComponentArrayHeight { get; }
public int OverallArrayWidth => IndividualArrayWidth * ComponentArrayWidth;
public int OverallArrayHeight => IndividualArrayHeight * ComponentArrayHeight;
public CompositeArray(int individualArrayWidth, int individualArrayHeight, int componentArrayWidth,
int componentArrayHeight)
{
IndividualArrayWidth = individualArrayWidth;
IndividualArrayHeight = individualArrayHeight;
ComponentArrayWidth = componentArrayWidth;
ComponentArrayHeight = componentArrayHeight;
_componentArray = new T[ComponentArrayWidth, ComponentArrayHeight][,];
}
public void SetIndividualArray(int x, int y, T[,] array)
{
if (x < 0 || x >= IndividualArrayWidth)
{
throw new ArgumentOutOfRangeException(nameof(x), x, $#"Must be between 0 and {IndividualArrayWidth - 1}");
}
if (y < 0 || y >= IndividualArrayHeight)
{
throw new ArgumentOutOfRangeException(nameof(y), y, $#"Must be between 0 and {IndividualArrayHeight - 1}");
}
if (array.GetLength(0) != IndividualArrayWidth || array.GetLength(1) != IndividualArrayHeight)
{
throw new ArgumentOutOfRangeException(nameof(array), $#"Must be between an array that is {IndividualArrayWidth} by {IndividualArrayHeight}");
}
_componentArray[x, y] = array;
}
public T GetOverallElement(int x, int y)
{
if (x < 0 || x >= OverallArrayWidth)
{
throw new ArgumentOutOfRangeException(nameof(x), x, $#"Must be between 0 and {OverallArrayWidth - 1}");
}
if (y < 0 || y >= OverallArrayHeight)
{
throw new ArgumentOutOfRangeException(nameof(y), y, $#"Must be between 0 and {OverallArrayHeight - 1}");
}
int whichArrayX = x / IndividualArrayWidth;
int innerX = x % IndividualArrayWidth;
int whichArrayY = y / IndividualArrayHeight;
int innerY = y % IndividualArrayHeight;
return (_componentArray[whichArrayX, whichArrayY][innerX, innerY]);
}
}
Note that I create a rectangularly jagged rectangular array. It took a bit to figure out the syntax.
Note that there is no copying at all. You only pay for two integer divisions and two integer modulus operations per element access. If you only use 2x2 arrays, you could reduce that to two bit-shifts and two bit-tests (since division by two is a simple bit-shift, and checking for even/odd is simply a test of the least significant bit).
Here's some code that exercises that class:
int[,] array00 = new int[,]
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int[,] array01 = new int[,]
{
{11, 12, 13},
{14, 15, 16},
{17, 18, 19}
};
int[,] array10 = new int[,]
{
{21, 22, 23},
{24, 25, 26},
{27, 28, 29}
};
int[,] array11 = new int[,]
{
{31, 32, 33},
{34, 35, 36},
{37, 38, 39}
};
CompositeArray<int> bigArray = new CompositeArray<int>(array00.GetLength(0), array00.GetLength(1), 2,2);
bigArray.SetIndividualArray(0, 0, array00);
bigArray.SetIndividualArray(0, 1, array01);
bigArray.SetIndividualArray(1, 0, array10);
bigArray.SetIndividualArray(1, 1, array11);
var shouldBe2 = bigArray.GetOverallElement(0, 1);
var shouldBe6 = bigArray.GetOverallElement(1, 2);
var shouldBe28 = bigArray.GetOverallElement(5, 1);
var shouldBe16 = bigArray.GetOverallElement(1, 5);
var shouldBe32 = bigArray.GetOverallElement(3, 4);

I think the best you can do is copy chunks of 3 values as they are all the source values that are contiguous in the destination array:
var ans = new int[6,6];
for (int row = 0; row < 2; ++row) {
for (int col = 0; col < 2; ++col) {
var srcArray = chunk_array[row, col];
for (int subRow = 0; subRow < 3; ++subRow) {
Array.Copy(srcArray, subRow*3, ans, subRow*6+row*18+col*3, 3);
}
}
}
Some performance testing doesn't show much optimization of this code possible.

Related

Pair Sum problem - c# code doesn't produce expected output-- please assist

public static int FindMaxNumForMaxSum(int[] nums, int k)
{
int retVal = 0;
int N = nums.Length;
var counter = 1;
var map = new Dictionary<int, int>();
for (var i = 0; i < N; i++)
{
if (nums[i] == retVal)
{
counter++;
continue;
}
var complement = k - nums[i];
retVal = complement;
if (nums[i] == complement)
{
if (!map.ContainsKey(complement))
{
map.Add(complement, counter);
}
else
{
map[complement] = counter++;
}
}
else
{
map.Add(complement, counter);
}
}
return counter;
}
Above is my code.
Problem description below:
Given a list of n integers arr[0..(n-1)], determine the number of different pairs of elements within it which sum to k.
If an integer appears in the list multiple times, each copy is considered to be different; that is, two pairs are considered different if one pair includes at least one array index which the other doesn't, even if they include the same values.
The above solution doesn't see to produce expected output and also there is a problem of adding duplicate keys in a dictionary.
Example 1
n = 5
k = 6
arr = [1, 2, 3, 4, 3]
output = 2
The valid pairs are 2+4 and 3+3.
Example 2
n = 5
k = 6
arr = [1, 5, 3, 3, 3]
output = 4
Example 3
arr = [2, 3, 6, 7, 4, 5, 1]
output = 3

Missing number -n to n [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
There is a number N (i.e., N = 3).
I create an array from -N to N (i.e. {-3, -2, -1, 0, 1, 2, 3})
I randomly remove a number from the array (i.e. {-3, -2, 0, 1, 2, 3}, removed -1)
I shuffle the Array (i.e. {-2, 0, 2, 3, -3, 1})
Write a function
public int FindMissing(int[] arr)
That takes the shuffled Array from the initial steps and identifies and returns the array's missing number.
I've done it like this, but I think I did it wrong:
public partial class findMissingNumber
{
public static int FindMissing(int[] arr, int N)
{
int summ = (N - 1) * N / 2;
int sumarr = 1;
for (int i = 1; i < arr.Length; i++)
{
sumarr += arr[i];
}
return summ - sumarr;
}
public static void Main()
{
Console.WriteLine(FindMissing(new int[] { -2, 0, 2, 3, -3, 1 }, 3));
Console.ReadLine();
}
}
The sum of all the numbers in an array [-N, N] is 0.
If an element is missing it'll be 0 minus the missing number.
If 1 is missing, sum = 0 - 1, therefore the missing number is -sum. Except when 0 is missing.
With LINQ is very easy:
using System.Linq;
class findMissingNumber
{
public static int FindMissing(int[] arr)
{
return (arr.Contains(0)) ? -arr.Sum() : 0;
}
public static void Main()
{
Console.WriteLine(FindMissing(new int[] { -2, 2, 1, 3, -3, -1 }));
}
}
Of course if you know that the array will always miss a number you don't even need to check if 0 is missing and it all boils down to -arr.Sum()
Without LINQ is a little longer, but works in the same way:
public static int FindMissing(int[] arr)
{
int sum = 0;
if (Array.FindIndex(arr, x => x == 0) < 0)
return 0;
Array.ForEach(arr, x => sum += x);
return -sum;
}
Again, if you know that an element will alwas be missing, you can avoid looking for zero
I used lambdas, but you can write your predicate as you like https://zetcode.com/csharp/predicate/

How can I sort multiple two dimensional arrays so that the first row is sorted into bins and the second row is summed up?

I am going to have a number of two-dimensional arrays that I would like to summarize into a single two-dimensional array. The first row is composed of doubles that represent mass, while the second row is composed of doubles that represent intensity.
//example 1 two-dimensional array
[145.56, 246.44, 346.55, 204.78]
[14, 30, 58, 49]
//example 2 two-dimensional array
[151.62, 223.18, 389.78, 266.96]
[67, 56, 23, 47]
I would like to summarize the two-dimensional arrays by sorting the mass doubles in the first row into bins of equal length, and then summing the pertinent intensity double up. So, assuming the mass bins had a length of 50, the summarized two-dimensional array using the two examples above would be:
//tentative example summarized two-dimensional array
[100-150, 150-200, 200-250, 250-300, 300-350, 350-400]
[14, 67, 135, 47, 58, 23 ]
I have so far tried to create a for loop that would first check which bin the mass would fall into by iterating over a nested for loop of the , and then add the intensity to previous intensity values.
double binSize = 50;
double[] binArray = new double[someNumberOfBins]
double[] summedIntensities= new double[numberOfTheirSummedIntensities];
for(i=0; i<twoDimensionalArray.GetLength(1); i++){
double currentMass= twoDimensionalArray[0,i];
for(j=0; j<binArray.GetLength(1); j++) {
if(currentMass> (binArray[j] - binSize) && currentMass <= (binArray[j] + binSize)) {
double currentIntensity = twoDimensionalArray[1,i];
summedIntensities[j] += currentIntensity;
}
}
//somehow combine the binArray with summedIntensities array into a two dimensional array
However, there are some problems in the a design of this algorithm. Firstly, I do not know how to set up the binArray so that the numbers in it properly reflect the range of in my two-dimensional arrays. I also am not sure how to combine the binArray with the summedIntensities array into a two-dimensional array, or whether this is even practical for this particular case.
Is there another way of making the binArray that is more fitting with my purpose of creating a summarized two-dimensional array, or are there any other glaring problems with this algorithm?
Here is my algorithm:
Note 1: in result array the first row will be '100', '150', '200'... You can construct a struct or use Dictionary<string,int> if you want it as "100-149", "150-199"...
Note 2: i calculated the interval as [100-149], [150,199], [200,249]... modify last condition to change it if you need to
static void Main(string[] args)
{
double[,] array1 = new double[2, 4] { { 145.56d, 246.44d, 346.55d, 204.78d }, { 14d, 30d, 58d, 49d } };
double[,] array2 = new double[2, 4] { { 151.62d, 223.18d, 389.78d, 266.96d }, { 67d, 56d, 23d, 47d } };
double[,] finalArray = DoWork(array1, array2,50);
}
private static double[,] DoWork(double[,] arrayLeft, double[,] arrayRight, int binLength)
{
//union of arrays
double[,] newArray = new double[2, arrayLeft.GetLength(1) + arrayRight.GetLength(1)]; //2x8 array
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < arrayLeft.GetLength(1); j++)
{
newArray[i, j] = arrayLeft[i, j];
}
for (int j = arrayLeft.GetLength(1); j < arrayLeft.GetLength(1) + arrayRight.GetLength(1); j++)
{
newArray[i, j] = arrayRight[i, j-4];
}
}
//sorting first row
for (int i = 0; i < newArray.GetLength(1)-1; i++)
{
for (int j = i+1; j < newArray.GetLength(1); j++)
{
if (newArray[0, i] > newArray[0, j])
{
double temp0 = newArray[0, j];
double temp1 = newArray[1, j];
newArray[0, j] = newArray[0, i];
newArray[1, j] = newArray[1, i];
newArray[0, i] = temp0;
newArray[1, i] = temp1;
}
}
}
//determine the number of bins and their intervals
double minMass = newArray[0, 0]; //145.56
double maxMass = newArray[0, newArray.GetLength(1) - 1]; //389.78
double minBinLowerValue = 0; //since you're working with mass i ignore the negative values
while (minBinLowerValue + binLength < minMass) minBinLowerValue += binLength; //100
double maxBinHigherValue = minBinLowerValue;
while (maxBinHigherValue < maxMass) maxBinHigherValue += binLength; //400
double numberOfBins = (maxBinHigherValue - minBinLowerValue) / binLength; //6
//creation of result array
double[,] resultArray = new double[2, Convert.ToInt32(numberOfBins)]; //2x6 array
//fill intervals to first row
for (int i = 0; i < resultArray.GetLength(1); i++)
{
resultArray[0, i] = minBinLowerValue + binLength * i;
}
//fill the sums
for (int i = 0; i < resultArray.GetLength(1); i++)
{
double sum = 0;
for (int j = 0; j < newArray.GetLength(1); j++)
{
if(resultArray[0,i] <= newArray[0,j] && resultArray[0, i] + binLength > newArray[0, j]) //modify this condition
{
sum += newArray[1, j];
}
}
resultArray[1, i] = sum;
}
return resultArray;
}
Here you go, I used a dictionary to store the summed values. The key is a bin number.
Note: If you want to make your solution better, I would use a class with 2 props (mass and intensity) I did not make this solution because am not sure if you have the freedom to have a class or if you are stuck with with input you got.
using System;
using System.Collections.Generic;
{
class Program
{
static void Main(string[] args)
{
double[] bins1 = { 145.56, 246.44, 346.55, 204.78 };
double[] values1 = { 14, 30, 58, 49 };
double[] bins2 = { 151.62, 223.18, 389.78, 266.96 };
double[] values2 = { 67, 56, 23, 47 };
int binSize = 50;
Dictionary<int, double> summedBins = new Dictionary<int, double>();
AddValuesToSummedBins(binSize, summedBins, bins1, values1);
AddValuesToSummedBins(binSize, summedBins, bins2, values2);
}
public static void AddValuesToSummedBins(int binSize, Dictionary<int, double> SummedBins, double[] Bins, double[] Values)
{
int i = 0;
foreach (double oneBin in Bins)
{
int binSet = binSize * ((int) oneBin / binSize);
if (!SummedBins.ContainsKey(binSet))
{
SummedBins.Add(binSet, Values[i]);
}
else
{
SummedBins[binSet] += Values[i];
}
i++;
}
}
}
}
If you are flexible about your data format, you can use LINQ to do this in a very small amount of code.
You would need to store your data pairs as a class with Mass and Intensity properties, instead of separate items in a 2D array.
Assuming this class to store your data:
public class DataElement
{
public double Mass { get; set; }
public double Intensity { get; set; }
}
You could use the following function:
public List<DataElement> Summarize(IEnumerable<DataElement> data, int range)
{
return data.GroupBy(de => Math.Floor(de.Mass / range) * range,
(range, g) => new DataElement {
Mass = range,
Intensity = g.Sum(d => d.Intensity)
})
.OrderBy(de => de.Mass)
.ToList();
}
This function takes all of your data as a single IEnumerable, and runs it thought LINQ's GroupBy function.
The first argument is an expression that determines how to group items together. For your purpose, I simply round down to the nearest multiple of the range argument (50 in your example, but anything should work).
The 2nd argument is an expression that returns the final output of a group, given the key of the group (the rounded down Mass), and the elements that were grouped together. I just return a new DataElement with e Mass of the rounded down Mass, and an Intensity equal to the Sum of the Intentities of the grouped item.
The result is then sorted by Mass before returning the result.
This produces the following output from the input you specified in the question (from LINQPad's Dump function):
You could use it like this (available as a LINQPad file):
void Main()
{
var data1 = new List<DataElement>{
new DataElement{Mass = 145.56, Intensity = 14},
new DataElement{Mass = 246.44, Intensity = 30},
new DataElement{Mass = 346.55, Intensity = 58},
new DataElement{Mass = 204.78, Intensity = 49},
};
var data2 = new List<DataElement>{
new DataElement{Mass = 151.62, Intensity = 67},
new DataElement{Mass = 223.18, Intensity = 56},
new DataElement{Mass = 389.78, Intensity = 23},
new DataElement{Mass = 266.96, Intensity = 47},
};
var result = Summarize(data1.Concat(data2), 50);
}

List items calculation [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
Let's say I have a list / array of integers, i.e:
{1, 2, 3, 4}
Is there a way to get every single possible combination of additions and add them to another list / array?
Like this:
1+2, 1+3, 1+4,
2+3, 2+4,
3+4,
1+2+3, 1+2+4, 1+3+4,
2+3+4,
1+2+3+4
So the end-result would be (without duplicates):
{3, 4, 5, 6, 7, 8, 9, 10}
With more specific to int list you can do that
static List<int> GetCombination(List<int> list, List<int> combinations, int sumNum, bool addNumberToResult = false)
{
if (list.Count == 0) {
return combinations;
}
int tmp;
for (int i = 0; i <= list.Count - 1; i++) {
tmp = sumNum + list[i];
if(addNumberToResult){
combinations.Add(tmp);
}
List<int> tmp_list = new List<int>(list);
tmp_list.RemoveAt(i);
GetCombination(tmp_list,combinations,tmp, true);
}
return combinations;
}
and to call it simply do
List<int> numbers = new List<int>(){1,2,3,4,5};
List<int> possibleCombination = GetCombination(numbers, new List<int>(), 0);
and to remove duplicate
possibleCombination.Distinct()
If you want it orderer you can call
possibleCombination.Distinct().OrderBy(itm => itm)
or
possibleCombination.Distinct().OrderByDescending(itm => itm)
C# fiddle
Edit : As Pierre rightly pointed out, the code did not stick to the question, I corrected accordingly, adding an parameters for adding or not the numbers to the result list.
Based on this great answer here is a version that will allow you to eliminate the "small subset"(*)
public static List<List<T>> GetCombination<T>(List<T> inputList, int minimumItems = 1)
{
int count = (int)Math.Pow(2, inputList.Count) - 1;
List<List<T>> result = new List<List<T>>(count + 1);
if (minimumItems == 0)
result.Add(new List<T>());
for (int i = 1; i <= count; i++)
{
List<T> combinason = new List<T>(inputList.Count);
for (int j = 0; j < inputList.Count; j++)
{
if ((i >> j & 1) == 1)
combinason.Add(inputList[j]);
}
if (combinason.Count >= minimumItems)
result.Add(combinason);
}
return result;
}
Result:
>> { {1,2}, {1,3}, {2,3}, {1,2,3}, {1,4}, {2,4},
>> {1,2,4}, {3,4}, {1,3,4}, {2,3,4}, {1,2,3,4} }
From here a simple .Sum() on the subset:
Subsets.ForEach( s => result.Add(s.Sum()) );
As you wanted to clear every duplicate in the list:
DoublonList.Distinct();
C# fiddle
ps: (*) Can't find the word in english for groupe of only one element

Efficient conversion of an array into a two-dimensional one using LINQ

I want to do the below in a performant way in C#, preferably using LINQ.
Array[Length] to Array[Length/Row][Row] where Row and Length are variables.
You can use Buffer.BlockCopy to efficiently convert between n-dimensional arrays of blittable types:
int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
int rows = 2;
int columns = a.Length / rows;
int[,] b = new int[columns, rows];
Buffer.BlockCopy(a, 0, b, 0, sizeof(int) * a.Length);
// b[0, 0] == 1
// b[0, 1] == 2
// b[1, 0] == 3
// b[1, 1] == 4
// b[2, 0] == 5
// b[2, 1] == 6
This takes advantage of the fact that multi-dimensional (not jagged!) arrays are laid out continuously in memory by the CLR.
For non-blittable types, simply use some good ol' for loops.
That's not a two dimensional array, that's a jagged array. I assume that you mean Array[Length/Row,Row].
There isn't anything in LINQ that does exactly that, so you will have a bit of overhead if you want to use it. The most performant way is straight forward code:
public T[,] MakeRows<T>(T[] values, int rowSize) {
T[,] result = new T[values.Length / rowSize, rowSize];
int row = 0, col = 0;
foreach (T value in values) {
resul[row, col] = value;
if (++col == rowsize) {
col = 0;
row++;
}
}
return result;
}
Note: The method assumes that the items are evenly divisable into rows.

Categories

Resources