Rotate an array using LINQ syntax - c#

I am solving this problem of rotating an array and got algorithm and code working
int[] Rotate(int[] ar,int k)
{
if (k <= 0 || k > ar.Length - 1)
return ar;
Reverse(ar, 0, k - 1);
Reverse(ar, k, ar.Length - 1);
Reverse(ar, 0, ar.Length - 1);
return ar;
}
void Reverse(int[] ar,int start, int end)
{
while (start < end)
{
int temp = ar[start];
ar[start] = ar[end];
ar[end] = temp;
start++;
end--;
}
}
Now I want to do this in LINQ and I got the below code, I think this can be done much better.
int[] Rotate(int[] ar,int k)
{
if (k <= 0 || k > ar.Length - 1)
return ar;
int[] ar1=ar.Take(k-1).Reverse().ToArray();
int[] ar2=ar.Skip(k - 1).Take(ar.Length - k+1).Reverse().ToArray();
int[] ar3 = ar1.Concat(ar2).Reverse().ToArray();
return ar3;
}
This is a well known algorithm from Programming pearls - http://books.google.com/books?id=kse_7qbWbjsC&lpg=PA14&ots=DfzTzQCSar&dq=rotate%20an%20array%20programming%20pearls&pg=PA14#v=onepage&q&f=false
And in general how to develop my LINQ skills, if I am given a programming problem, right now I am only thinking in for loops or foreach loops, how to think in terms of linq operators. I am reading C# 4.0 nutshell, other than practicing any advice?

I'm not sure why you've got all the reversals, to be honest. How about this:
int[] Rotate(int[] ar,int k)
{
if (k <= 0 || k > ar.Length - 1)
return ar;
return ar.Skip(k) // Start with the last elements
.Concat(ar.Take(k)) // Then the first elements
.ToArray(); // Then make it an array
}
Here's a short but complete program to demonstrate it:
using System;
using System.Linq;
class Test
{
static int[] Rotate(int[] ar,int k)
{
if (k <= 0 || k > ar.Length - 1)
return ar;
return ar.Skip(k) // Start with the last elements
.Concat(ar.Take(k)) // Then the first elements
.ToArray(); // Then make it an array
}
static void Main()
{
int[] values = { 1, 2, 3, 4, 5 };
int[] rotated = Rotate(values, 3);
Console.WriteLine(string.Join(", ", rotated));
}
}
Output: 4, 5, 1, 2, 3
EDIT: I've just noticed one major difference between my code and your original: yours modifies the original array - mine returns a new array with the rotated values. So would your LINQ code, but it means if you were testing my code with something that only looked at the original array, you wouldn't see the rotation.
LINQ is designed to work this way in general - it favours returning a new sequence over modifying an existing one.

Starting with your code:
int[] ar1=ar.Take(k-1).Reverse().ToArray();
int[] ar2=ar.Skip(k - 1).Take(ar.Length - k+1).Reverse().ToArray();
int[] ar3 = ar1.Concat(ar2).Reverse().ToArray();
Since you just want to get all of the remaining elements, the Take in the second line isn't needed.
ar1 and ar2 are just enumerated, so they don't need to be arrays. The ToArray calls aren't needed. With a bit of creative renaming thrown in, we have:
IEnumerable<int> revFirst = ar.Take(k-1).Reverse();
IEnumerable<int> revLast = ar.Skip(k-1).Reverse();
int[] ar3 = revFirst.Concat(revLast).Reverse().ToArray();
Now we have
rev ( rev(first) + rev(last) )
distributing the outer rev gives
rev ( rev(last) ) + rev ( rev(first) )
which is the same as
last + first
applying the same operations to the code gives
IEnumerable<int> first = ar.Take(k-1);
IEnumerable<int> last = ar.Skip(k-1);
int[] ar3 = last.Concat(first).ToArray();
which further simplifies to
int[] ar3 = ar.Skip(k-1).Concat(ar.Take(k-1)).ToArray();
and now we have Jon Skeet's answer so we must be done.

this is my solution
public int[] solution(int[] A, int K) {
// write your code in C# 6.0 with .NET 4.5 (Mono)
if (A.Length <= 1)
{
return A;
}
var rotate = K % A.Length;
var leftSide = A.Length - rotate;
var arr1 = A.AsParallel().Skip(leftSide).Take(rotate);
var arr2 = A.AsParallel().Take(leftSide);
return arr1.Concat(arr2).ToArray();
}
you can check my github. I also have some unit tests for other cases and other codidlity lessons and challenges

Related

Why do the elements of the array change when they shouldn't?

I am writing code for Merge sort, I use object arrays with lists which are then sorted and merged, I know it's a bit strange and there is probably a better way to do it. When I recurse back to function in the code below, there a more elements than there should be, and I just don't get why it happens.
public static void RecurseSort(Array arr)
{
Array ForWork = arr;
if (ForWork.Length == 1)
{
MessageBox.Show("recurs finish");
}
else
{
List<object> ForRecurse = new List<object>();
Array arrCopy = new object[ForWork.Length / 2];
for (int i = 0; i < ForWork.Length - 1; i = i + 2)
{
List<int> r1 = (List<int>)ForWork.GetValue(i);
List<int> r2 = (List<int>)ForWork.GetValue(i + 1);
if (i == ForWork.Length - 3)
{
List<int> r3 =
(List<int>)ForWork.GetValue(ForWork.Length - 1);
r2.Add(r3[0]);
}
ForRecurse.Add(CompareAndMerge(r1, r2));
}
arrCopy = ForRecurse.ToArray();
RecurseSort(arrCopy);
}
}
So the arrCopy has the correct number of elements but literally when I press 'continue' in the visual studio debbuger, arr[3] has count of 3, when it should have been 2.
Divide and conquer - split it to smaller problems and solve them.
Copy
How do you copy data from array A to array B, for example what will be the result of:
int[] src = { 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270 };
int[] dest = { 17, 18, 19, 20 };
int length = 2;
Array.Copy(src, 4, dest, 2, length);
Arithmetics
How do you divide array to 2 - divide by 2, but if the size is uneven ex: 7, what will be the result of:
var length = 7;
var result = length / 2;
Type constraints
var length = 7d;
var result = length / 2;
Merging 2 sorted array
In merge sort you use another sort, for example insertion sort if you have only few elements left, ex: 20. So if you are given following insertion sort, how do you split array of 37 random numbers to 2 partisions, sort them and merge them.
static class InsertionSort<T> where T : IComparable {
public static void Sort(T[] entries, Int32 first, Int32 last) {
for (var index = first + 1; index <= last; index++)
insert(entries, first, index);
}
private static void insert(T[] entries, Int32 first, Int32 index) {
var entry = entries[index];
while (index > first && entries[index - 1].CompareTo(entry) > 0)
entries[index] = entries[--index];
entries[index] = entry;
}
}
In addition, debugger is your friend.
It is difficult to say as you did not provide the full text of the working example. But I suspect that you keeping references to objects in the array when you should not.
But most importantly I suggest you rewrite your code so it does not use casts. Try using List of List - List<List<int>> - it will be strongly typed and clear your algorithm. Also, I suggest writing it for concrete type to sort - int and later moving to Generic implementation with your method that will accept type <T> to sort.

Finding the closest integer value, rounded down, from a given array of integers

I am trying to figure out the best way to find the closest value, ROUNDED DOWN, in a List of integers using any n that is between two other numbers that are stored in a List. The all integers in this situation will ALWAYS be unsigned, in case that helps.
The assumptions are as follows:
The List always starts at 0
The List is always sorted ASC
All integers in the List are unsigned (no need for Math.Abs)
The number for comparison is always unsigned
For example:
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int theAnswer; // should be 8500
for (int i = 0; i < numbers.Count; i++) {
if (i == numbers.Count - 1) {
theAnswer = numbers[i];
break;
} else if (myNumber < numbers[i + 1]) {
theAnswer = numbers[i];
break;
}
}
The previous code example works without any flaws.
Is there a better more succint way to do it?
You can use List<T>.BinarySearch instead of enumerating elements of list in sequence.
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int r=numbers.BinarySearch(myNumber);
int theAnswer=numbers[r>=0?r:~r-1];
Filter list obtaining all values less than the myNumber and return last one:
theAnswer = numbers.Where(x => x <= myNumber ).Last();
A list can be indexed.
Start at the index in the middle of the list. If you found the exact number, you are good. If the number is less than the target number, search in the middle of the range from the start of the list to one less than the middle of the list. If the number is greater than the target number, work with the opposite half of the list. Continue this binary search until you find either an exact match, or the adjacent numbers that are smaller and larger than the target number.
Select the smaller of the two.
Please try this code:
List<int> numbers = new List<int>() { 0, 2000, 4000, 8000, 8500, 9101, 10010 };
int myNumber = 9000;
int theAnswer = numbers[numbers.Count - 1];
if (theAnswer > myNumber)
{
int l = 0, h = numbers.Count - 1, m;
do
{
m = (int)((double)(myNumber - numbers[l]) / (double)(numbers[h] - numbers[l]) * (h - l) + l);
if (numbers[m] > myNumber) h = m; else l = m;
}
while ((h - l) != 1);
theAnswer = numbers[l];
}

Union of two arrays

Given two arrays
int arr1[n]
int arr2[m]
where n > m
Need to write a union of two arrays into one.
For example, if the input arrays are:
int arr1[] = {1, 3, 4, 5, 7}
int arr2[] = {2, 3, 5, 6}
Then program should create new array Union as {1, 2, 3, 4, 5, 6, 7}
Implementation can be in C# or Java.
In order to solve it first of all need to to sort the arrays using Merge Sort
and then do the union
I looked in the net but did not find the elegant way . Every code that I looked
was full of IF's.
Please advice what is the most quick and elegant way to do it
You are correct that merging the two lists as is done in Merge Sort is the most efficient thing to do. This assumes that the two lists are already sorted, as in your example. Here is an example of how to implement merge:
function merge(left,right)
var list result
while length(left) > 0 or length(right) > 0
if length(left) > 0 and length(right) > 0
if first(left) ≤ first(right)
append first(left) to result
left = rest(left)
else
append first(right) to result
right = rest(right)
else if length(left) > 0
append first(left) to result
left = rest(left)
else if length(right) > 0
append first(right) to result
right = rest(right)
end while
return result
From here, simply do not include repeats in the final output.
If its an elegant MergeSort you are looking then nothing is more elegant than a recursive function :-)
Here it is :
This is a divide and conquer strategy. We basically divide the array into smaller arrays , sort the smaller arrays and merge them back.
public static void mergesort(int a[],int left, int right){
/*
* Time : O(n log n)
* Space : O(n)
*/
int b[] = new int[right -left+1];
domergesort(a,left,right,b);
}
public static void domergesort(int a[],int left,int right, int b[]){
if(left < right){
int mid = (left+right)/2;
domergesort(a,left,mid,b);
domergesort(a,mid+1,right,b);
merge(a,left,mid,a,mid+1,right,b);
for(int k=left;k<=right;k++)
a[k] = b[k-left];
}
}
Not many ifs too ..
Source : My Blog (http://cloudingitup.blogspot.com/p/reading-guide-arrays.html)
To merge them together as a Union :
public static void merge( int a[], int al, int ar, int b[], int bl, int br, int c[]){
// al : a's left index ar : a's right index c: merged array
int i= al;
int j = bl;
int k=0;
int prev = c[0];
while ( i<= ar && j <= br){
if (a[i] <= b[j])
if (prev != a[i]) // Too keep the union distinct
c[k++] = a[i++];
else
i++;
else
if (prev != b[j]) // Too keep the union distinct
c[k++] = b[j++];
else
j++;
prev = c[k-1];
}
while (i <= ar)
{
if (prev != a[i])
c[k++] = a[i++];
else
i++;
prev = c[k-1];
}
while (j <= br)
{
if (prev != b[j])
c[k++] = b[j++];
else
j++;
prev = c[k-1];
}
}
A driver code to illustrate the code :
int arr1[] = {1,1, 3, 4,4,4,5, 7};
int arr2[] = {2, 3, 5, 6,6,8};
int c[] = new int[8];
merge(arr1,0,7,arr2,0,5,c);
for(int i=0;i<8;i++)
System.out.print(c[i]);
Output: 12345678
public static void printUnion(int ar1[],int ar2[]) {
int m = ar1.length;
int n = ar2.length;
int i=0,j=0;
while(i<m && j<n) {
if( ar1[i] <ar2[j]) {
System.out.println(ar1[i]);
i++;
}else if(ar1[i] > ar2[j]) {
System.out.println(ar2[j]);
j++;
}else {
System.out.println(ar1[i]);
i++;
j++;
}
}
while(i < m)
System.out.println(ar1[i++]);
while(j < n)
System.out.println(ar2[j++]);
}
Same code will work for intersection with minimal changes....
In interviews, they usually want to see you solve the problem, rather than using library calls (e.g. arr1.union(arr2) probably wouldn't cut it.)
This is off the top of my head, but something like this should work, and I think is O(n^2). It assumes both arrays are sorted.
union.rb
arr1 = [0,2,4,9,11,12,13]
arr2 = [3,4,7,9,10,11]
def union(n, m)
if n.last > m.last
arr1 = n; arr2 = m
else
arr1 = m; arr2 = n
end
union_array = []
j = 0
arr1.each do |x|
while j < arr2.length && arr2[j] < x
if arr2[j] < x
union_array << arr2[j] unless arr2[j] == union_array.last
j += 1
end
end
union_array << x
end
union_array
end
puts union(arr1, arr2)
this method should work fairly well, and it will decide which array is bigger so there doesn't need to necessarily be a defined order.
Java:
public static <T> T[] combine(T[] a1, T[] a2)
{
return combine(a1, a2, a1.length + a2.length);
}
public static <T> T[] combine(T[] a1, T[] a2, int maxlength)
{
T[] front = null;
T[] back = null;
if(a1.length >= a2.length)
{
front = a1;
back = a2;
}
else
{
front = a2;
back = a1;
}
int len = front.length + back.length;
if(len > maxlength)
{
len = maxlength;
}
int n = 0;
T[] result = Arrays.copyOf(front, len);
int c = 0;
for(int i = 0;i < front.length;i++)
{
if(i < front.length && c < result.length)
{
result[c] = front[i];
c++;
}
if(i < back.length && c < result.length)
{
result[c] = back[i];
c++;
}
}
return result;
}
this is obviously not the most efficient method, but it does completely work. It also includes a capping, if you want to merge them, but only get the first, let's way 5 items, then you can add a parameter of 5 to the method.
You can actually get rid of a lot of waste, there's a lot of messy stuff in here, I'm away from my IDE so it's off my head, I may have stuff that's not needed.

Efficient algorithm for removing an array from another array

I'm wondering if anyone knows a better (as in faster) algorithm/solution to solve my problem:
In my program I have an array of uints, from which I want to remove the entries contained in another uint array. However, I cannot use the union of the sets, because I need to keep duplicate values. Badly worded explaination, but the example should make it a bit clearer:
uint[] array_1 = new uint[7] { 1, 1, 1, 2, 3, 4, 4};
uint[] array_2 = new uint[4] { 1, 2, 3, 4 };
uint[] result = array_1 .RemoveRange(array_2);
// result should be: { 1, 1, 4 }
This is my current best idea; but it's fairly slow:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
int current_source_length = source_array.Length;
for (int i = 0; i < entries_to_remove.Length; i++)
{
for (int j = 0; j < current_source_length; j++)
{
if (entries_to_remove[i] == source_array[j])
{
// Shifts the entries in the source_array.
Buffer.BlockCopy(source_array, (j + 1)* 4 , source_array, j * 4, (current_source_length - j) * 4);
current_source_length--;
break;
}
}
}
uint[] new_array = new uint[current_source_length];
Buffer.BlockCopy(source_array, 0, new_array, 0, current_source_length * 4);
return new_array;
}
So again, can someone come up with a more clever approach to achieve what I want?
Thanks!
What about using a Dictionary<uint,int> using the uint number as the key and the number of times the number occurs as the value?
var source = new Dictionary<uint,int>();
source.Add(1,3);
source.Add(2,1);
source.Add(3,1);
source.Add(4,2);
var remove = new uint[]{ 1, 2, 3, 4 };
for (int i = 0; i<remove.Length; i++) {
int occurences;
if (source.TryGet(remove[i], out occurences)) {
if (occurences>1) {
source[remove[i]] = occurences-1;
} else {
source.Remove(remove[i]);
}
}
}
This would do what you want as far as I understand it, they key is reference counting of the number of occurrences and then using the remaining reference count (if > 0) as the number of times a number has to be emitted:
public static uint[] RemoveRange(this uint[] source_array, uint[] entries_to_remove)
{
var referenceCount = new Dictionary<uint, int>();
foreach (uint n in source_array)
{
if (!referenceCount.ContainsKey(n))
referenceCount[n] = 1;
else
referenceCount[n]++;
}
foreach (uint n in entries_to_remove)
{
if (referenceCount.ContainsKey(n))
referenceCount[n]--;
}
return referenceCount.Where(x => x.Value > 0)
.Select(x => Enumerable.Repeat(x.Key, x.Value))
.SelectMany( x => x)
.ToArray();
}
EDIT: This won't help you, since you want to keep duplicates.
I'm leaving it here for people who don't want duplicates.
Create a HashSet<T> from the second list, then call List<T>.RemoveAll with the hashset's Contains method.
var unwanted = new HashSet<uint(...);
list.RemoveAll(unwanted.Contains);
If you don't want to remove them in-place, you can use LINQ:
list.Except(unwanted);
Except will build two hashsets and return items one at a time (deferred execution0
If the arrays aren't sorted, sort them. Initialize 3 indexes to 0. 's'(source) and 'd' (dest) index the big array A, 'r' indexes the "toRemove" array B.
While r<B.length,
While B[r] > A[s], A[d++]= A[s++].
If B[r]==A[s], s++.
r++.
Endwhile.
While s<A.length, A[d++]= A[s++].
A.length = d.
This takes no extra space, and runs in O(N), (or N lg N if they are initially unsorted), compared to the N^2 I your original solution.
You can try using Linq here,
var resultarray = array1.Except(array2);

Using arrays with recursion

Now that I am using recursion to calcuate the sum of numbers, I want to do something slightly different. The following is my code that will sum the numbers 1,2,3,4,5. How would I modify my code to place the numbers 1, 2, 3, 4, 5 into an array and then use it in the recursion method? I have tried so many different attempts and I am apparently missing something. I know that in the recursion method, that I want to use the Length property of the array to control it.
Susan
static void Main(string[] args)
{
Console.WriteLine(Sum(5));
Console.Read();
}
static int Sum(int value)
{
if (value > 0)
{
return value + Sum(value - 1);
}
else
{
return 0;
}
}
let seq = [1;2;3;4;5]
let rec samp nums =
match nums with
| [] -> 0
| h::t -> h + samp t
static int Sum(int[] a, int index = 0)
{
if (a[index] == a[a.Length - 1])
{
return a[a.Length - 1];
}
return a[index] + Sum(a, index + 1);
}
static void Main()
{
int[] arr = {1, 2, 3, 9, 15};
Console.WriteLine(Sum(arr));
}
I'm a beginner too but this is my solution and it works for me.
What about using a Stack?:
Stack<int> stack = new Stack<int>(new int [] {1,2,3,4,5});
Console.WriteLine(SumStack(stack));
public static int SumStack(Stack<int> input)
{
return input.Count > 0 ? input.Pop() + SumStack(input) : 0;
}
Sniff, sniff, smells like homework to me.
However, a hint. Adding all the elements of an array of length 'n' is the same as adding all the elements of an array of length 'n-1', then adding the value of element 'n'.
The result of adding all the elements of an array of length '1' is just the value of the one element
I believe that you need to pass the array and the index in your Sum function to control the recursivity.
Of if your no good with lambda expressions or you only have .net 2.0, this is simple enough;
static void Main(string[] args)
{
int[] myArray = new int[5] {1,2,3,4,5 };
Console.WriteLine(Sum1(myArray));
Console.Read();
}
private static int Sum1(int[] myArray)
{
if (myArray.Length > 0)
{
int lengthZeroAdjusted = myArray.Length - 1;
int element = myArray[lengthZeroAdjusted];
Array.Resize<int>(ref myArray, lengthZeroAdjusted);
return element + Sum1(myArray);
}
else
{
return 0;
}
}
You're wanting to perform an operation that is commonly referred to as "fold" a.k.a. "reduce".
Luckily, the .NET team did your (home)work for you!
static int sum(int[] values)
{
return values.Aggregate<int>((hd, tl) => hd + tl);
}
You can rewrite it for easier readability if you like. ;)
EDIT: usage example
int[] values = new int[]{1,2,3,4,5};
Console.WriteLine(sum(values));
Recursion essentially means doing the small part, and giving the larger part to somebody else.
Now if you have to 'n' elements of array, you ask somebody to give you sum of last n-1 elements,
and just first one yourself ... just handle the case where there is nothing to be done ...
a pseudo code would be :
sum array start_index = if ( start_index >= length(array) ) return 0
else return array[start_index] = sum array (start_index + 1)
print (sum array 0 )

Categories