Get array slices in length order - c#

I have the following code to get a list of all possible slice start/end indexes, in order of descending slice length. I then iterate over the list and use it to slice up an array, breaking when I get a slice that I am looking for. I do this because I am looking for the largest slice that matches other parameters and I am looking to short cut past the other possible slices once I've found one.
I would prefer a couple of nested for loops to check the slice and move on, instead of having to get every possible range and sort them first, since the array can be up to a billion or so items large. I can't for the life of me figure out how to do it, or even how to phrase the question to search for it. Any help is appreciated.
byte[] data1 = { 54, 87, 23, 87, 45, 67, 7, 85, 65, 65, 3, 4, 55, 76, 65, 64, 5, 6, 4, 54, 45, 6, 4 };
List<Tuple<int, int>> ranges = new List<Tuple<int, int>>();
for (int i1 = 0; i1 < data1.Count(); i1++)
{
for (int i2 = i1 + 1; i2 < data1.Count(); i2++)
{
ranges.Add(new Tuple<int, int>(i1, i2));
}
}
ranges = ranges.OrderByDescending(x => x.Item2 - x.Item1).ToList();

If I understand the question correctly, you are looking for the largest subarray of an array (which you are calling a "slice"…maybe a term from some other programming language?) that meets some specific conditions. In your question, you are unspecific about the conditions themselves, so I assume that part is not important.
It seems what you are having difficulty with is arranging your code so that you necessarily inspect the longest subarrays first.
If all of that is correct, then you just need to arrange your loops differently. Currently, you are picking a starting index and then finding all subarrays that start at that index. Instead, since you want the longest subarrays to be inspect first, you should pick the length of the subarray, starting with the longest possible length, and select all subarrays that can be that long.
For example:
for (int i = data1.Length; i > 0; i--)
{
for (int j = 0; j < data1.Length - i + 1; j++)
{
// inspect subarray starting at index j, having length i
}
}

You may enumerate the slices directly by a couple of nested loops:
bool found = false;
for (int sliceLen = data1.Length; !found && sliceLen > 0; sliceLen--)
for (int sliceStart = 0; !found && sliceStart + sliceLen <= data1.Length; sliceStart++)
if (found = (
data1[sliceStart] == data1[sliceStart + sliceLen - 1] // check your condition here
))
Console.WriteLine($"Found: {sliceStart}:{sliceLen}");
Demo: https://ideone.com/lZRNJm

I figured it out. Here's what I needed, to iterate over each array slice in reverse length order.
byte[] data1 = { 54, 87, 23, 87, 45, 67, 7, 85, 65, 65, 3, 4, 55, 76, 65, 64, 5, 6, 4, 54, 45, 6, 4 };
for (int length = data1.Count() - 1; length > 0; length--)
{
int numberOfSlicesForLength = data1.Count() - length;
for (int start = 0; start < numberOfSlicesForLength; start++)
{
byte[] sliceValues = data1.Skip(start).Take(length);
}
}

Related

Last number in an array becomes first

I know that's easy, but I don't understand how I should do it.
1 23 29 18 43 20 5
to
5 1 23 29 18 43 20
I think we should use for-loop:
for (int i = 0; i < numbers.Count - 1; i++)
{
}
but I don't know what to do in it. Something like numbers[i] = numbers[i - 1] but it isn't working. I think there are some if checks which I miss.
The most straightforward way that comes to mind is a reverse loop.
int[] numbers = { 1, 23, 29, 18, 43, 20, 5};
int lastVal = numbers[numbers.Length - 1];
for (int i = numbers.Length -1; i > 0; i--)
numbers[i] = numbers[i-1];
numbers[0] = lastVal;
Just looping from the end (after saving the last value) and moving "up" the values, finally replacing the first value with the last
Here's a oneliner:
var numbers = new[] {1, 23, 29, 18, 43, 20, 5};
numbers = new[] {numbers.Last()}.Concat(numbers.Take(numbers.Length - 1)).ToArray();
This creates a new array containing the last element, then concatenates it with the original array excluding the last element.
What you want to do is make another array of the same size as the original one, then assign the last element and loop through the array up to the previous to last element.
Something like this:
int[] original = {1, 23, 29, 18, 43, 20, 5};
int[] altered = new int[original.length];
altered[0] = original[original.length - 1];
for (int i = 1; i < original.length - 1; i++)
{
altered[i] = original[i - 1];
}
You can perform a left rotation to the table by six positions on your case and create the requested new table
int[] myArray = new int[] { 1, 23, 29, 18, 43, 20, 5 };
var newArray = LeftRotationByD(myArray, 6);
and your function for the rotation would be:
private static int[] LeftRotationByD(int[] a, int k)
{
int[] b = new int[a.Length];
int index;
int length = a.Length;
int place;
for (int i = 0; i < length; i++)
{
index = i - k;
place = length + index;
if (index >= 0) b[index] = a[i];
else b[place] = a[i];
}
return b;
}
You can use this method to shift right:
void ShiftRight(int[] array, int count)
{
var clone = (int[])array.Clone();
for (var i = 0; i < array.Length; i++)
array[(i + count) % array.Length] = clone[i];
}
And use it this way:
var a = new int[] { 1, 2, 3, 4 };
ShiftRight(a, 1);

C# split 1D array into 2D array for every Nth value

I have a 1D array of ints:
int[] array = { 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31, 32,33, 34,40,41,42,43, 44};
I would like to divide this 1D array into a 2D array of 4 rows and 5 columns, where the first 5 values goes into row 1, the next 5 in row 2 and so on. The final result should look like this:
array2D:
[[10, 11, 12, 13, 14]
[20, 21, 22, 23, 24]
[30, 31, 32, 33, 34]
[40, 41, 42, 43, 44]]
In reality the array will be much longer(maybe 100+ rows), but the number of columns is 5 and number of rows is dividable by 5. I have simplified for example. This is what I have tried so far:
int[] array = { 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31, 32,33, 34,40,41,42,43, 44};
int[,] array2D = new int[(array.Length/5),5];
int count_0 = 1;
int count_1 = 1;
int count_2 = 1;
int count_3 = 1;
int count_4 = 1;
for (int i = 0; i < array.Length; i++)
{
if (i < 5)
{
// works for the first 5 values:
array2D[0, i] = array[i];
}
// I tried this approach for the rest where I try to say that if Im at index 5,
//and every 5th element from here, append to it to index[i,0] of array2D and so on.
// This do not work, and is what I need help with.
else if (i >= 5 && i % 5 == 0)
{
array2D[count_0, 0] = array[i];
count_0++;
}
else if (i >= 6 && i % 5 == 0)
{
array2D[count_1, 1] = array[i];
count_1++;
}
else if (i >= 7 && i % 5 == 0)
{
array2D[count_2, 2] = array[i];
count_2++;
}
else if (i >= 8 && i % 5 == 0)
{
array2D[count_3, 3] = array[i];
count_3++;
}
else if (i >= 9 && i % 5 == 0)
{
array2D[count_4, 4] = array[i];
count_4++;
}
}
Of course for this example I could just say if > 5 && <10 {append to array2D} and if > 10 && <15 {append to array2D} and so on, but I want something that works for a large array of hundreds of values. If someone has a smarter way to do this please let me know.
Thank you for any help!
You can just calculate the indexes:
for(int i=0;i<array.Length;i++)
array2D[i/5, i%5] = array[i];
You can calculate the indexes easily using simple division. The row is calculated by the dividing i with the wanted column numbers. The column is simply the reminder of that division.
using System;
public class Program
{
public static T[,] SplitInto2DArray<T>(T[] array, int rows, int columns) {
T[,] result = new T[rows, columns];
for (int i = 0; i < array.Length; i++) {
result[i / columns, i % columns] = array[i];
}
return result;
}
public static void PrintArray<T>(T[,] array) {
for (int i = 0; i < array.GetLength(0); i++) {
for (int j = 0; j < array.GetLength(1); j++) {
Console.Write(array[i, j] + " ");
}
Console.WriteLine();
}
}
public static void Main()
{
int[] array = { 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 40, 41, 42, 43, 44};
int[,] splittedArray = SplitInto2DArray(array, 4, 5);
PrintArray(splittedArray);
}
}
You can accomplish with LINQ using Enumerable.GroupBy.
array.GroupBy(x => x / 5)
.Select(x => x.ToArray())
.ToArray()

Multidimensional array column sorting

assume i create this code to generate the idv-th random number. But i have a difficulty in sorting the array depends on the last column.
let say the individual size is [idv, width] = [8,6]
and i want to sort all the row with column 6th... and i want to take the 4 top list in the array after it sorted. How can i implement this case to the code??
public static void population(double[,] individual, int width, int idv, Random rnd)
{
for (int i = 0; i < idv; i++)
{
Console.Write("individual {0} :\t", i+1);
for (int j = 0; j < width; j++)
{
individual[i, j] = Math.Round(rnd.NextDouble() * 10, 2);
Console.Write("{0} ", individual[i, j]);
}
Console.WriteLine("\n");
}
}
Thank you
I suggest you using jagged arrays double[][] instead of 2d ones double[,]. Jagged array is just an array of array which you can easily sort, filter, etc. usually with a help of Linq:
double[][] individual = new double[][] {
new double[] {81, 82, 83, 84, 85, 86},
new double[] {11, 12, 13, 14, 15, 16},
new double[] {41, 42, 43, 44, 45, 46},
new double[] {31, 32, 33, 34, 35, 36},
new double[] {51, 52, 53, 54, 55, 56},
new double[] {21, 22, 23, 24, 25, 26},
new double[] {61, 62, 63, 64, 65, 66},
new double[] {71, 72, 73, 74, 75, 76},
};
double[][] fragment = individual
.OrderBy(line => line[line.GetUpperBound(0)]) // by last column
.Take(4)
.ToArray();
One more Linq to test the results:
String test = String.Join(Environment.NewLine, fragment
.Select(line => String.Join("\t", line)));
Console.Write(test);
The result is
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 35 36
41 42 43 44 45 46
If you use multidimensional arrays, there's no easy way to work with them using LINQ, you'll need to rely on good old for.
static void Main ()
{
// Input array
double[,] u = {
{ 1, 9, 3 },
{ 0, 3, 4 },
{ 3, 4, 5 },
{ 3, 6, 8 },
{ 3, 5, 7 },
};
// Get dimension sizes, specify column to order by
int count = u.GetLength(0), length = u.GetLength(1), orderBy = 2;
// Result array
double[,] v = new double[count, length];
// Construct a list of indices to sort by
var indices = Enumerable.Range(0, count).OrderBy(i => u[i, orderBy]).ToList();
// Copy values from input to output array, based on these indices
for (int i = 0; i < count; i++)
for (int j = 0; j < length; j++)
v[i, j] = u[indices[i], j];
PrintArray(u);
Console.WriteLine();
PrintArray(v);
}
static void PrintArray (double[,] a)
{
for (int i = 0; i < a.GetLength(0); i++) {
for (int j = 0; j < a.GetLength(1); j++)
Console.Write(a[i, j]);
Console.WriteLine();
}
}
If you need only top 4 rows, you can add Take(4) before ToList() call and adjust result array creation and copying of values into it appropriately.
Multidimenional arrays are more efficient and use less memory, so if your arrays are big enough or you need to work with them faster, you may need to write a little more code and use multidimenional arrays instead of jagged arrays which are easier to work with.
For rectangular array [,] you can copy the desired column in a single-dimensional array together with indices, sort it, and then get rows with first 4 indices.
static IEnumerable<Tuple<int, double>> GetColumn(int columnIndex, double[,] a)
{
for (int i = a.GetLowerBound(0); i <= a.GetUpperBound(0); i++)
yield return Tuple.Create(i, a[i, columnIndex]);
}
double [,] data = ...;
var column = GetColumn(4, data);
var top4Indices = column.OrderBy(v => v.Second)
.Take(4)
.Select(v => v.First);
foreach (int i in top4Indices)
for (int j = data.GetLowerBound(1); j <= data.GetUpperBound(1); j++)
data[i, j]...

c# quicksort algorithm doesnt proceed

I have just worked on implementation of quicksort in c# but then I have faced a such a problem. When I am using my function
static void QS(int[] arr, int left, int right){
int pivot = left;
int temp;
int i = left + 1;
int j = left + 1;
do {
if (arr [i] < arr [pivot]) {
temp = arr [j];
arr [j] = arr [i];
arr [i] = temp;
i++;
}
else{}
j++;
}while(j<=right);
temp = arr [pivot];
arr [pivot] = arr [i - 1];
arr [i - 1] = temp;
}
For an array
int[] arr = { 12, 9, 19, 8, 7, 13, 10, 71, 18, 34, 90, 15, 3 };
I get the results like this:
9, 12, 19, 8, 7, 13, 10, 71, 18, 34, 90, 15, 3.
Hours been spent on this I still can't quite understand why index i does not proceed. Maybe there are more problems than I think.
I omitted recursive calls to concentrate on fuction itself. I am using this pseudo-code:
Partiton(A,l,r)
//[input corresponds to A[l…r]]
p:=A[l]
i:=l+1
for
j=l+1 to r
if A[j] < p
swap A[j] and A[i]
i:=i+1
swap A[l] and A[i‐1]
Several things:
Youre missing the comparisons(while loops) within the do while loop that move the index pointers, and the recursive calls that make quicksort actually work. Remember when you swap your values, increment i and decrement j. Second, for the values i and j, dont add 1 to those indexes as they could give you out of bounds errors, I assume you will be calling quicksort like so: quicksort(arr, 0, arr.Length - 1);. Finally, please choose your pivot as the median value as it yields much faster sorting time and results, rather than choosing the first value in the array.
Heres how I would write this:
quicksort(arr[], begin, end)
{
pivot = (begin + end) / 2
left = begin;
right = end;
while (left <= right)
{
while (arr[left] < pivot)
{
left++;
}
while (arr[right] > pivot)
{
right--;
}
if (left <= right)
{
swap(arr, left, right);
left++;
right--;
}
}
//do your recursive call logic here
}

Duplicate values in an int array (best performance)

I have an array of numbers that have some duplicate values.
I want to find the first two duplicate numbers.
The real problem is it must be in best performance and I cant use LINQ it must be in classic codes.
The real question is about best performance so it means best answer is the fastest language and fastest algorithm.
I tried it in C#:
int[] numbers = {5, 2, 10, 18, 55, 100, 10, 50, 23, 6, 14, 25, 12};
int result1 = -1;
int result2 = -1;
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers.Length; j++)
{
if (numbers[j] == numbers[i] & i != j)
{
result2 = j;
result1 = i;
J = numbers.Length; //this will cause loop exit.
i = numbers.Length; //this will cause first loop to exit.
}
}
}
Console.Write("The result of search is {0} and {1}", result1, result2);
Console.ReadLine();
I will appreciate any answers ;)
Use a dictionary to store the numbers and where you found them, and when you find one that exists in the dictionary, you have your duplicate and its position. Adding and locating items in a dictionary are O(1) operations, so the algorighm is an O(n) operation:
int[] numbers = { 5, 2, 10, 18, 55, 100, 10, 50, 23, 6, 14, 25, 12 };
Dictionary<int, int> found = new Dictionary<int,int>();
int result1 = -1, result2 = -1;
for (int i = 0; i < numbers.Length; i++) {
int number = numbers[i];
int pos;
if (found.TryGetValue(number, out pos)) {
result1 = pos;
result2 = i;
break;
}
found.Add(number, i);
}
Console.Write("The result of search is {0} and {1}", result1, result2);
Console.ReadLine();
For some additional performance you can preallocate space for all the items in the dictionary that it might need. This uses more memory in the average case, but keeps the dictionary from repeatedly allocating more space when it grows:
Dictionary<int, int> found = new Dictionary<int,int>(numbers.Length);

Categories