I have a list of integer arrays, and i want to check for each array if the array if chronological, if it is not I want it to be removed from the list.
At the moment I do it like this:
for (int i = 0; i < allXcombis.Count(); i++)
{
bool remove = false;
for (int j = 0; j < allXcombis[i].Length; j++)
{
if (allXcombis[i].Count() - 1 > j)
if (allXcombis[i][j] != allXcombis[i][j + 1] - 1)
remove = true;
}
if (remove)
allXcombis.Remove(allXcombis[i]);
}
but I am not really happy with this code, I think it can be done easier.
First, I would probably extract the checking that the array is “chronological” into its own method and made it more efficient, by returning from the loop early:
bool IsChronological(int[] array)
{
for (int i = 0; i < array.Length - 1; i++)
{
if (array[i] != array[i + 1] - 1)
return false;
}
return true;
}
And then I would simply use RemoveAll():
allXcombis.RemoveAll(a => !IsChronological(a));
This way, you get concise, readable code and you don't have to worry about indexes in the list (as others mentioned, you have a bug in your code, because you're not careful about the indexes).
When you are removing from list inside loop, you need either to fix loop variable or to loop backwards. Then, you don't need () after Count. And you can break from loop after assigning remove = true, this will improve performance.
for (int i = allXcombis.Count - 1; i >= 0; i--)
{
bool remove = false;
for (int j = 0; j < allXcombis[i].Length; j++)
{
if (allXcombis[i].Length - 1 > j)
{
if (allXcombis[i][j] != allXcombis[i][j + 1] - 1)
{
remove = true;
break;
}
}
}
if (remove)
allXcombis.Remove(allXcombis[i]);
}
If by chronological you mean sorted, then you need to check < not !=.
Also you can simplify some things. The most important is when you find that it's not sorted to break out of the inner loop, so that you don't keep iterating.
Also you need to decrease i when you remove, because you'll skip some arrays otherwise (say if i = 2 and you remove the second array, then the third array becomes second, but i will be 3 on the next iteration, so you'll skip it)
for (int i = 0; i < allXcombis.Count; i++)
{
for (int j = 0; j < allXcombis[i].Length-1; j++)
{
if (allXcombis[i][j] > allXcombis[i][j + 1] - 1)
{
allXcombis.Remove(allXcombis[i]);
i--;
break;
}
}
}
I agree with svick in the use of a dedicated method like he proposed "IsChronological" but I would like to add a little bit of security and performance to this method:
bool IsChronological(int[] array)
{
bool result = ((array == null) || (array.Length == 0)) ? false : true; //Null or empty arrays are not chronological by definition (also avoid exceptions)
if (result)
{
result = (array.Length == 1) ? true : false; //Arrays with only one element are chronological by definition
if (!result)
{
int length = array.Length - 1;
int index = 0;
while ((index < length) && (array[index] == array[index] + 1))
index++;
result = (index == array.length);
}
}
return result;
}
Related
I'm trying to make a scan of an array where it follows the index with the numbers inside and I don't understand why it gives me this exception. I cant add any more details its a pretty straight forward question.
using System;
public class Program
{
public static bool IsPerfect(int[] arr)
{
int next=0, done=0,i;
while (done == 0)
{
i = arr[next];
arr[next] = 10;
next = arr[i];
if (i == 0)
done = 1;
}
for(int j = 0; j < arr.Length; j++)
if (arr[j] != 10)
return false;
return true;
}
public static void Main()
{
int[] arr = { 3, 0, 1, 4, 2 };
if (IsPerfect(arr) == true)
Console.WriteLine("is perfect");
if (IsPerfect(arr) == false)
Console.WriteLine("boooo");
}
}
You are not specifying the functioning for duplicates... Use a method to check for duplicates and as soon as you encounter a duplicate element exit the loop... It will work fine! 👍
ok for anyone intrested the problem was lying in the second if, and the "next = arr[i];" the first i changed because it made more sense and the second and main problem was the other if. because i had the second condition it ran the method twice and with the changed values it returned an error.
the solution was to put else instead.
Reverse engineering: we mark visited items and if all items are visted, then we have a "Perfect" array.
Problem: we mark item with 10 which can be an index (what if array has, say, 15 items)?
Solution: let's mark by -1 (definitely not an index - an array can have negative number of items) and check if item has been marked:
Tricky moment: we should assign -1 to the current arr[i] item but use its initial value to be assigned to i. Sure, we can save i and put it as
for (int i = 0; i >= 0 && i < arr.Length; ) {
int nextI = arr[i];
arr[i] = i;
i = nextI;
}
but let's put in a short modern way: (i, arr[i]) = (arr[i], -1);
Code:
public static bool IsPerfect(int[] arr) {
// In public method we must be ready for any input; null included
if (arr == null)
return false; // or throw new ArgumentNullException(nameof(arr));
// Do we have a valid array?
for (int i = 0; i < arr.Length; ++i)
if (arr[i] < 0 || arr[i] >= arr.Length)
return false;
// Note the condition: we read the next item - arr[i] -
// if and only if i is within range
// Note, that we have nothing to increment / decrement
for (int i = 0; i >= 0 && i < arr.Length; )
(i, arr[i]) = (arr[i], -1); // note the assignment: both i and arr[i] in one go
// We have marked all that we could.
// Do we have unmarked items?
for (int i = 0; i < arr.Length; ++i)
if (arr[i] != -1) // ... yes, we have and thus
return false; // arr is not perfect
return true;
}
Please, fiddle
So I'm just trying to understand how bubblesort (it may help me with other algorithms when I see this kind of stuff as well) works with the nested for loop.
I noticed that most people will do the loops like so:
public static void BubbleSort(int[] arr, int arr_size)
{
int i, j, temp;
bool swapped;
for (i = 0; i < arr_size - 1; i++)
{
swapped = false;
for (j = 0; j < arr_size - i -1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
{
break;
}
}
}
I have done it like this (only slightly different; note the nested loop size check:
public static void BubbleSort(int[] arr, int arr_size)
{
int i, j, temp;
bool swapped;
for (i = 0; i < arr_size - 1; i++)
{
swapped = false;
for (j = 0; j < arr_size - 1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (swapped == false)
{
break;
}
}
}
And it seems to work with every check I've done so far.
I guess to sum it up, I am wondering why the first loop would be the size - 1 (I know this is because of the whitespace at the end) and the nested loop will be the size - i - 1 (at least I have seen this a lot). Thanks for any feedback !
The effect of the inner loop:
for (j = 0; j < arr_size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
is finding the maximum element in the array and placing it to the last position. Hence, for i == 0 (the index from the outer loop), it moves it to the last array position. For i == 1, the array's overall maximum element is already at the last array position, and hence it does not need to be processed again. For i == 2 etc. the situation is the same. In other words, the array is being sorted from 'backward' by 'bubbling' (hence the algorithm's name) the maximum elements up each iteration.
There is a nice step-by-step example on Wikipedia.
In your second example, by omitting the - i in the for loop clause, you are just unnecessarily checking array elements that are already in place from previous (outer loop) iterations and hence cannot change anymore.
I am trying to make a bubble sort program that can sort array of integers from bottom.
var list = new int[] {5,0,2}; //array
for (int i = 0; i < list.Length; i++)
{
while (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
}
Console.WriteLine(string.Join(",", list));
I get the index out of range error in the while (list[i] > list[i+1]). What is wrong with my code? Is my while condition bad?
is my while condition bad?
No, your for loop condition is incorrect. Look at the loop here and consider what that says about the value of i within the body of the loop.
for (int i = 0; i < list.Length; i++)
That ensures that list[i] is always valid. But you're using list[i + 1], so you need to make sure that i + 1 is a valid index into the array. The simplest way to do that is to just reduce the limit in the condition:
for (int i = 0; i < list.Length - 1; i++)
That will remove the exception, but you'll be left with this while loop:
while (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
You don't modify the value of i within the loop, which means it's only ever going to execute once - as soon as you've executed the body of that loop, the condition will become false. So it would be clearer to write it as an if statement:
if (list[i] > list[i+1])
{
list[i] = list[i + 1];
}
Now I suspect that's not really what you want - you probably want to swap values rather than just assigning, and you probably want a single loop, but that's rather beyond the scope of the immediate question.
Thx everyone for help, finally i made it work with adding a bool that guarantees checking the array if it is needed to repeat inner loop again:
var list = new int[] {5,7,0,2}; //array
bool alert = true;
while (alert == true)
{
alert = false;
for (int i = 0; i < list.Length - 1; i++)
{
while (list[i] > list[i + 1])
{
int temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
alert = true;
}
}
}
Console.WriteLine(string.Join(",", list));
Console.ReadKey();
I've been having trouble trying to get the proper index of list(I). Basically the algorithm sorts through a list of consecutive numbers such as 1,3,5,7,9,13 and returns which number is missing (11 in this case). My problem is that temp stays at -1, any idea on why? From my understanding, temp should increase as i gets incremented
public static int FindMissing(List<int> list)
{
int difference;
int missing = 0;
for (int i = 0; i < list.Count; i++)
{
difference = list[1] - list[0];
int temp = list.IndexOf(i);
if (temp > 0)
{
if (list[i] - list[i - 1] != difference)
{
missing = list[i - 1] + difference;
}
}
}
return missing;
}
Alexandru Popa gave me a good answer, but for future people looking at this thread, someone showed me the continue keyword which ended up working like this
public static int FindMissing(List<int> list)
{
int difference;
int missing = 0;
for (int i = 0; i < list.Count; i++)
{
if (i == 0) continue;
difference = list[1] - list[0];
if (list[i] - list[i - 1] != difference)
{
missing = list[i - 1] + difference;
}
}
return missing;
}
We need to make some changes in your code.
First, let's check if the list contains at least two elements, otherwise we shouldn't run the algorithm.
if(list.Count <= 2)
return 0;
Second, move the declaration and initialization of difference out of the loop. As difference is constant, you shouldn't calculate it on each iteration.
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
Third, let's start the loop from index 2 as there's no need to check if difference equals difference.
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
for (int i = 2; i < list.Count; i++)
{
}
Fourth, there is no need to check if your list contains its index, that's the sketchy part of your code, you only need to look at the differences between each neighbors. When one of them doesn't match up your initial difference you got your missing number. And we should return immediately, otherwise it can be overwritten if there are other missing elements in your list.
public static int FindMissing(List<int> list)
{
if(list.Count <= 2)
return 0;
int difference = list[1] - list[0];
for (int i = 2; i < list.Count; i++)
{
if (list[i] - list[i - 1] != difference)
{
return list[i - 1] + difference;
}
}
return 0;
}
However this algorithm does not check for the integrity of the list. It only finds the first missing element in your list. It does not tell us whether the list contains other missing elements or not.
According to the comment in your question - you said that your list consist of elements: 1040,1220,1580.
Now in the for loop your index (i) will have the values 0,1,2.
Then your temp value will try to find the IndexOf the values of i - 0,1,2.
But in your list, there are no such values. Your values are 1040,1220,1580. So the IndexOf will always return -1.
This is why you always see -1.
Clear up a bit your question and code.
I am learning C# these days and still a beginner.
While practicing creating methods, I made this method that yields the sum of the members of a numeric array (my codes are massive and I am not good at math).
VS returns an ArgumentOutOfRangeException Error, but I don't know how to fix this.
Please save me!
public static int SumAll(int[] a)
{
List<int> sum = new List<int>();
int sumAll;
if (a.Length == 0)
{
sumAll = 0;
}
else
{
sum[0] = a[0];
for (int i = 1; i < (a.Length - 1); i++)
{
sum[i] = sum[i - 1] + a[i];
}
sumAll = sum[a.Length - 1];
}
return sumAll;
}
Use the += addition assignment operator:
public static int SumAll(int[] a)
{
int sumAll = 0;
for (int i = 0; i < (a.Length - 1); i++)
{
sumAll += a[i];
}
return sumAll;
}
The ArgumentOutOfRangeException is typically to do with an item out of the range of an array, collection or list.. Because you use a List<int> sum you are not adding items to it. sum.Add(a[i]); and that's why you get the exception; the sum variable doesn't have any items.
The reason you're getting that exception is because you are trying to assign a value to an index in the List that doesn't exist yet when you do this:
sum[0] = a[0];
Instead, you should just use the .Add method to add items to the List. Once they're added, you can access them by index. The reason for this is that the list is not pre-populated to any set size (whereas an array is), so to begin with there is nothing at [0].
sum.Add(a[0]);
You will also get this exception here:
sumAll = sum[a.Length - 1];
This is because the sum List will only contain a.Length - 2 items (your loop stops when i == a.Length - 1). This is a bug in your code! You should be using i < a.Length as the condition:
for (int i = 1; i < a.Length; i++)
This way you are looping through ALL the items in your a array.
Your method would then look something like this (notice I also added a check for a == null):
public static int SumAll(int[] a)
{
if (a == null) return 0;
List<int> sum = new List<int>();
int sumAll;
if (a.Length == 0)
{
sumAll = 0;
}
else
{
sum.Add(a[0]);
for (int i = 1; i < a.Length; i++)
{
sum.Add(sum[i - 1] + a[i]);
}
sumAll = sum[a.Length - 1];
}
return sumAll;
}
Now, this code could be simplified if you wanted, by removing the list, starting with sumAll = 0, and then just adding each item from a to it in your loop:
public static int SumAll(int[] a)
{
if (a == null) return 0;
int sumAll = 0;
for (int i = 0; i < a.Length; i++)
{
sumAll += a[i];
}
return sumAll;
}
Or you can really shorten it by using the System.Linq extension method, Sum:
public static int SumAll(int[] a)
{
return a == null ? 0 : a.Sum();
}