Order array such that all positive numbers appear first - c#

i am writing a code in c# to sort an array, i want all the negative values in the right side and all the positive values in the left side, the should not be in decreasing order
namespace SortApp
{
class Program
{
static void Main(string[] args)
{
int[] newInt = new int[] { 5, -2, -1, -4, -20, 6, 7, -14, 15, -16, 8, 9, 10 };
int size = 12, i= 0; // or newInt.Length
for (i = 0; i < newInt.Length; i++)
{
if (newInt[i] < 0 && newInt[size] > 0)
{
int temp = newInt[i];
newInt[i] = newInt[size];
newInt[size] = temp;
size--;
}
}
for (i = 0; i < newInt.Length; i++)
{
Console.Write(newInt[i]);
Console.Write(" ");
}
}
}
}
but the output is something like this (-20 is on wrong side):
5 10 9 8 -20 6 7 -14 15 -16 -4 -1 -2
but the intended output is:
5 10 9 8 15 6 7 -14 -20 -16 -4 -1 -2
Why is my code not producing my intended output?

Your solution incorrectly decides when to finish the loop. Also, it unconditionally increments i in the loop header, and never decrements size even when it points to a negative number.
Here is how you fix it:
for (i = 0; i < size ; ) {
if (newInt[i] < 0 && newInt[size] >= 0) {
int temp = newInt[i];
newInt[i] = newInt[size];
newInt[size] = temp;
size--;
i++;
continue;
}
if (newInt[i] >= 0) {
i++;
}
if (newInt[size] < 0) {
size--;
}
}
Here is a demo on ideone.
You can rewrite this loop using a more readable identifiers for your left and right pointers, rather than using i and size. This would make your algorithm look more "symmetric" in the code, to recognize the symmetry in its design:
int left = 0, right = newInt.Length-1;
while (left < right) {
if (newInt[left] < 0 && newInt[right] >= 0) {
int temp = newInt[left];
newInt[left] = newInt[right];
newInt[right] = temp;
right--;
left++;
continue;
}
if (newInt[left] >= 0) {
left++;
}
if (newInt[right] < 0) {
right--;
}
}
Here is an ideone link to the alternative implementation.

Try this solution:
var newInt = new[] {5, -2, -1, -4, -20, 6, 7, -14, 15, -16, 8, 9, 10};
var solution = newInt.GroupBy(i => i > 0).
SelectMany(g => g).
ToArray();
The problem with your algorithm is that when you decrease size, you end up having newInt[size] point at a negative value, and the if block is not entered.

The general idea for a pretty easy easy solution would be to start one index, call it left at the beginning of the array, and another, called right at the end of the array.
Increment left until you find a negative number, or until left == right. When you hit a negative number, decrement right until you find a positive number, or until right == left.
If left is indexing a negative number and right is indexing a positive number, swap the two items and start incrementing left again.
The general idea, not tested:
int left = 0;
int right = a.Length-1;
while (left < right)
{
if (a[left] < 0)
{
while (right > left)
{
if (a[right] >= 0)
{
// swap here
int temp = a[left];
a[left] = a[right];
a[right] = temp;
break;
}
--right;
}
}
++left;
}

This yields the desired order with a minimum of loops
int[] newInt = new int[] { 5, -2, -1, -4, -20, 6, 7, -14, 15, -16, 8, 9, 10 };
int lt = 0;
int rt = newInt.Length - 1;
while (true) {
// Find first negative number
while (newInt[lt] >= 0 && lt < rt) {
lt++;
}
// Find last positive number
while (newInt[rt] < 0 && rt > lt) {
rt--;
}
if (lt == rt) {
break; // Finished
}
// Swap
int temp = newInt[lt];
newInt[lt] = newInt[rt];
newInt[rt] = temp;
}
//TODO: Print result

if you can use generics and linq than the easiest solution would be :
int[] newInt = new int[] { 5, -2, -1, -4, -20, 6, 7, -14, 15, -16, 8, 9, 10 };
newInt.ToList().Sort();
newInt.Reverse();
newInt = newInt.ToArray();
Hope this will help !!

Related

Else statement is not recognized in C# what am I missing?

In C# the program is supposed to count how many valid and invalid values were entered by comparing them to the array and then give a total of the correct and incorrect inputs, but when I enter numbers that are outside of the bounds of the if statement the code from the if statement still runs. I've gone back and reviewed videos and the textbook and I cannot see where my if else statement is lacking.
int[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };
int count = 0;
Console.WriteLine("Enter a value between 0 and 10");
foreach (int v in values)
{
Console.ReadLine();
if (values[v] >= 0 || values[v] <= 10)
{
Console.WriteLine("Enter a value");
count++;
}
else
{
Console.WriteLine("Invalid Entry");
count++;
}
}
Console.WriteLine("You entered {0} correct values", count);
Console.WriteLine("You entered {0} incorrect values", count);
Console.ReadKey();
}
}
(values[v] >= 0 || values[v] <= 10) will always return true, all numbers are either less than 10 or greater than zero. Presumably you want an and (&&) operator to grab values between 0 and 10 inclusive
Also, foreach iterates through the values of an array, not the index, so you don't need to reference values[v], you can just reference v directly (although in your case values[v]==v). Calling values[v] in a foreach runs a huge risk of indexOutOfBounds exceptions. If you want to iterate through the index a straight for loop is more appropriate:
for(int i = 0; i< values.Length; i++)
var myVal = values[i];
Final Edit, you aren't actually checking the user's input
var input = Console.ReadLine();
//you never bothered capturing the user's input with a variable
decimal myNum;
if (decimal.TryParse(input, out myNum)) //did the user give a number?
{
//use myNum instead of values[v]
}
else
{
//process bad input
}
There's a bunch of stuff you can do to make things cleaner, (like removing your array altogether and using for(int i = 0; i< 10; i++) instead, for example), but good code doesn't happen on day 1 (my first few projects make me wanna throw up now), you got this friend.
You have a foreach loop, you do not need to use
if (values[v] >= 0 || values[v] <= 10)
instead, use
if(v >= 0 || v <= 10)
plus your if statement will always return true because the value you have in your array of int is greater than or equals to 0 or less than or equals to 10.
Try to change the array from
int[] values = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };
to
int[] values = { -5, 1, 2, 3, 11, 5, 6, 13, 8, 9, 15, };
and you should have 4 incorrect count, provided you separate the correct count and incorrect count instead of adding them together using the count.
Separate them into validCount and invalidCount

What's wrong with my merge sort implementation [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm sure I'm making an incredibly silly mistake but I've been at this for hours and I just want my code to sort prettily... Something is going wrong with implementation when odd numbers come into the equation.
Below is my MergeSplit method:
static List<Motor> MergeSplit(List<int> ListX)
{
int n = ListX.Count;
if (n <= 1)
return ListX;
List<int> left = new List<int>();
List<int> right = new List<int>();
for (int i = 0; i < n; i++)
{
if (i < (n / 2))
left.Add(ListX[i]);
else
right.Add(ListX[i]);
}
left = MergeSplit(left);
right = MergeSplit(right);
return Merge(left, right);
}
And here is the Merge method:
static List<int> Merge(List<int> ListX, List<int> ListY)
{
List<int> result = new List<int>();
int i = 0;
while (ListX.Count > i && ListY.Count > i)
{
if (ListX[i] > ListY[i])
{
result.Add(ListY[i]);
result.Add(ListX[i]);
}
else
{
result.Add(ListX[i]);
result.Add(ListY[i]);
}
i++;
}
//If odd, add the rest to the result
if (ListX.Count > ListY.Count)
result.Add(ListX[ListX.Count - 1]);
else if (ListY.Count > ListX.Count)
result.Add(ListY[ListY.Count - 1]);
return result;
}
Thanks for your help!
Update
The algorithm just doesnt sort correctly with certain inputs
The problem is your Merge routine
You are comparing the left and right and adding them to the list respectively, where you should be comparing the heads, and adding the lowest to the result, and removing that head respectively for the next comparison
This is the pseudo code from wiki https://en.wikipedia.org/wiki/Merge_sort
while left is not empty and right is not empty do
if first(left) ≤ first(right) then
append first(left) to result
left := rest(left)
else
append first(right) to result
right := rest(right)
You can see why thats important here
As you can see its actually comparing the first left and first right, then adding them to the result and removing that item from the list. which is vastly different from what you are doing. you either need 2 index variables, or remove the items from the list
while (listX.Count > 0 && listY.Count > 0)
if (listX[0] > listY[0])
{
result.Add(listY[0]);
listY.RemoveAt(0);
}
else
{
result.Add(listX[0]);
listX.RemoveAt(0);
}
if (listX.Count > 0)
result.AddRange(listX);
else if (listY.Count > 0)
result.AddRange(listY);
Just for fun, i found this was easier to play with queues, they seem to like this sort of thing
private static Queue<int> Merge(Queue<int> left, Queue<int> right)
{
var result = new Queue<int>();
while (left.Count > 0 && right.Count > 0)
result.Enqueue(left.Peek() > right.Peek() ? right.Dequeue() : left.Dequeue());
foreach (var item in left)
result.Enqueue(item);
foreach (var item in right)
result.Enqueue(item);
return result;
}
private static Queue<int> MergeSplit(Queue<int> list)
{
var n = list.Count;
if (n <= 1)
return list;
var left = new Queue<int>();
var right = new Queue<int>();
for (var i = 0; i < n; i++)
if (i < n / 2)
left.Enqueue(list.Dequeue());
else
right.Enqueue(list.Dequeue());
left = MergeSplit(left);
right = MergeSplit(right);
return Merge(left, right);
}
Usage
var list = new List<int> { 8, 7, 6, 4, 43, 23, 435, 76, 7, 7877, 5, 421, 2 };
var results = MergeSplit(new Queue<int>(list));
Console.WriteLine(string.Join(", ", results));
Output
2, 4, 5, 6, 7, 7, 8, 23, 43, 76, 421, 435, 7877
Full Demo Here

If exit array, enter from the other side

How can I do this for example if I have 1, 2, 3, 4, 5, 6, 7 array and I am in 4th position (number 5) and if you have to move it to the right 4 positions you should be in position 1 (number 2). The same goes with negative numbers but you move to left. I guess there is a need of while(true) loop?
Lets assume i is the index and n is the size of the array.
For positive i the needed index = i%n
For negative i i%n returns negative residue, so the needed index is n+i%n
You can use
int index(int i, int n) {
return i%n < 0 ? n + (i%n) : i%n;
}
You can calculate your index like this:
var newIndex = (index + 4) % 7;
So the fourth position becomes (4+4) % 7 or 1.
Always clearer with named functions and followable code path instead of voodoo one liners that work
public void MyTest()
{
var testData = new[] { 1, 2, 3, 4, 5, 6, 7 };
Assert.AreEqual(2, TraverseCircularArray(testData, 5, 3));
Assert.AreEqual(6, TraverseCircularArray(testData, 2, -4));
}
private int TraverseCircularArray(int[] array, int currentIndex, int interval)
{
var i = array[currentIndex];
if (currentIndex + interval < 0)
i = array[array.Length + (interval + currentIndex)];
else if (currentIndex + interval >= array.Length)
i = array[currentIndex - interval - 1];
else
i = array[currentIndex + interval];
return i;
}

Increasing Array with Rows

Say I have an an array of numbers:
int[] that = new [] {1, 2, 3, 2, 4, 8, 9, 7};
I'm trying to display them so that the numbers that are increasing have their own line.
For example the result would be:
1 2 3
2 4 8 9
7
I'm able to do the first row using,
for (int i = 1; i < that.Length; i++)
{
if (that[i-1] < that[i])
{
Console.Write(that[i-1] + " ");
}
}
The thing is this works for the first row because 1-3 are increasing but stops after that.
I'm not exactly sure how to continue so that 2 4 8 9, then 7 are written.
I have a feeling this is homework so I'm going to leave the actual coding to you. But here's how to do it in plain language:
Have a variable where we store the previous value. Let's call it oldValue, and start it with zero (if you're only using positive numbers in your array).
Go through the array one item at a time.
Check to see if that number is larger than oldValue.
If FALSE, print the new line character. "\n" in C#.
Print that number and make oldValue equal that number.
Unless your numbers are finished get the next number and go to step 3.
You never create a new line.
int[] arr = new[] {1, 2, 3, 2, 4, 8, 9, 7};
for(var i = 0; i < arr.Length; i++){
if(i == 0 || ((i < arr.Length - 1) && arr[i] < arr[i + 1])){
Console.Write(arr[i]);
} else {
Console.Write("{0}\n", arr[i]);
}
}
Output:
123
2489
7
Couple of remarks:
Avoid the usage of this as a variable name. It's a reserved
keyword.
Use \n as a newline character.
There are a number of ways you can do this, either by appending a string with characters until a lesser one is reached and then using the Console.WriteLine() command to write the entire string at once, or (the easier way given your code) which is to simply test for the new value being lesser than the previous and inserting a newline character into your text.
// Start at zero
for (int i = 0; i < this.Length; i++)
{
// If this is not the first element in the array
// and the new element is smaller than the previous
if (i > 0 && this[i] < this[i-1])
{
// Then insert a new line into the output
Console.Write(Environment.NewLine);
}
Console.Write(this[i] + " ");
}
int[] numbers = new int[] { 1, 2, 3, 2, 4, 8, 9, 7 };
String orderedNumbers = String.Empty;
for (int i = 0; i < numbers.Length; i++)
{
if (i == 0 || numbers[i] > numbers[i - 1])
{
orderedNumbers += numbers[i].ToString();
}
else
{
orderedNumbers += System.Environment.NewLine + numbers[i].ToString();
}
}
MessageBox.Show(orderedNumbers);

construct an array of integers to achieve specific sequence

construct the shortest possible sequence of integers ending with A,
using the following rules:
the first element of the sequence is 1, each of the successive
elements is the sum of any two preceding elements (adding a single
element to itself is also permissible), each element is larger than
all the preceding elements; that is, the sequence is increasing.
For example, for A = 42, a possible solutions is [1, 2, 3, 6, 12, 24,
30, 42]. Another possible solution is [1, 2, 4, 5, 8, 16, 21, 42].
I have written the following but it fails on input of 456, by returning[1,2,4,8,16,32,64,128,200,256,456] , there are no numbers in the sequence that can be added together to get 200.
how can I fix the below code? what am I doing wrong?
public static int[] hit(int n)
{
List<int> nums = new List<int>();
int x = 1;
while (x < n)
{
nums.Add(x);
x = x * 2;
if (x > n)
{
nums.Add(n - (x / 2));
nums.Add(n);
}
}
nums.Sort();
int[] arr = nums.ToArray();
return arr;
}
I know there is gonna be a mathematical proof behind this, but my guess would be along the lines of dividing the number by 2, if it divides equally, repeat the process. If the there is a remainder, it would be 1. So you would have the integer quotient and the quotient plus one. Since one is guaranteed to be in the set, the larger of the 2 numbers is already taken care of. So just repeat the process for the smaller. This problem certainly implies a recursive solution that should be relatively trivial, so I will leave that up to the poster to implement.
I think I got it:
public Set<Integer> shortList(int n){
Set<Integer> result = new HashSet<Integer>();
Stack<Integer> stack = new Stack<Integer>();
result.add(n);
int num=n, den=0;
while(num>1){
while(num > den){
num--; den++;
if(num%den==0)
stack.push(num);
}//num>den
if(!stack.isEmpty()){
num = stack.pop();
result.add(num);
stack.clear();
}else{
result.add(num);
result.add(den);
}
den=0;
}
return result;
}//
Results (unsorted)
for 42: [1, 2, 3, 21, 6, 7, 42, 14]
for 15: [1, 2, 4, 5, 10, 15]
for 310: [1, 2, 155, 4, 5, 310, 10, 124, 62, 31, 15, 30]
Here is my solution in C++ (may be trivially changed to C#):
void printSequenceTo(unsigned n)
{
if (n == 1) { printf("1"); return; }
if (n & 1) {
int factor = 3;
do {
if (n % factor == 0) {
printSequenceTo(n / factor * (factor-1));
factor = 0;
break;
}
factor += 2;
} while (factor * factor <= n);
if (factor) printSequenceTo(n-1);
}
else
printSequenceTo(n/2);
printf(",%u", n);
}
Demonstration: http://ideone.com/8lXxc
Naturally it could be sped up using a sieve for factorization.
Note, this is significant improvement over the accepted answer, but it still is not optimal.
Here is my attempt. It may be optimised, but it shows my idea:
private static IEnumerable<int> OptimalSequence(int lastElement)
{
var result = new List<int>();
int currentElement = 1;
do
{
result.Add(currentElement);
currentElement = currentElement * 2;
} while (currentElement <= lastElement);
var realLastElement = result.Last();
if (lastElement != realLastElement)
{
result.Add(lastElement);
FixCollection(result, lastElement - realLastElement);
}
return result;
}
private static void FixCollection(List<int> result, int difference)
{
for (int i = 0; i < result.Count; i++)
{
if (result[i] == difference) break;
if (result[i] > difference)
{
result.Insert(i, difference);
FixCollection(result, difference - result[i-1]);
break;
}
}
}
Edit
I can't prove it formally but my answer and Chris Gessler's answer give sequences of the same size (at least I checked for numbers between 1 and 10000) because both algorithms compensate odd numbers.
Some examples:
Number 1535
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1024,1535
Number 2047
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047
Number 3071
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2048,3071
Number 4095
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095
Number 6143
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4096,6143
Number 8191
1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095,4096,8191
==============
Number 1535
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535
Number 2047
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047
Number 3071
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071
Number 4095
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095
Number 6143
1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071,6142,6143
Number 8191
1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095,8190,8191
public static int[] hit(int n)
{
List<int> nums = new List<int>();
nums.Add(n);
int x = 0;
int Right = 0;
int Left = 0;
do
{
//even num
if (n % 2 == 0)
{
x = n / 2;
//result of division is also even 20/2 = 10
if (x % 2 == 0 || n>10 )
{
nums.Add(x);
n = x;
}
else
{
nums.Add(x + 1);
nums.Add(x - 1);
n = x - 1;
}
}
//numbers that can only be divided by 3
else if (n % 3 == 0)
{
x = n / 3;//46/3 =155
Right = x * 2;//155*2 = 310
Left = x;//155
nums.Add(Right);
nums.Add(Left);
n = x;
}
//numbers that can only be divided by 5
else
{
x = n / 2;
Right = x + 1;
Left = x;
nums.Add(Right);
nums.Add(Left);
n = Left;
}
} while (n > 2);
nums.Add(1);
nums.Reverse();
int[] arr = nums.ToArray();
return arr;
}

Categories