My current task is to find a score from an array where the highest/lowest scores have been taken away, and if the highest/lowest occur more than once (ONLY if they occur more than once), one of them can be added
So the programflow can be written as:
- Find the highest item of the array
- Find the lowest item of the array
- Find the number of occurance of the highest item of the array
- Find the number of occurance of the lowest item of the array
- Remove the first highest item found
- Remove the first lowest item found
- Sum together the remaining items
- Export/Print the results
So you will have 8 methods without the ExitProgram() method.
Review
Naming
Based on the naming conventions for C#, all methodnames should be written using the PascalCasing style. So findOccurrence should be FindOccurrence and findScore should be FindScore
So based on the list of tasks above the methods should be named
- FindHighestItem() or GetHighestItem()
- FindLowestItem() or GetLowestItem();
- FindNumberOfHighestOccurance() or GetCountOfOccurance()
- FindNumberOfLowestOccurance() or GetCountOfOccurance()
- RemoveHighestItems() or SetArrayitemsByValueToZero()
- RemoveLowestItems() or SetArrayitemsByValueToZero()
GetHighestItemIndex() GetLowestItemIndex() GetNormalizedArray() which returns a new array or SetArrayitemsByValueToZero() which manipulates the items in the array - SumItems()
- Print()
Style
Opening brackets should be placed on the line below the statement so
for (int i = 0; i < scores.Length; i++) {
should be
for (int i = 0; i < scores.Length; i++) {
Programflow
By combining some of these tasks you are violating the single responsible principle.
The findScore() method
- is searching for the highest and lowest item in the array
- removes the highest and lowest item from the array (basically add only the items which aren't highest or lowest to the new array)
- is summing the items of this new array stated above
- is printing/exporting the sum
Refactoring
For getting the highest/lowest item in the array we can use the Math.Max() and Math.Min() methods. For finding the highest item we will initialize the var highestValue with Int32.MinValue and for finding the lowest item we will initialize the var lowestValue with Int32.MaxValue.
Based of the comment as it is not allowed for this assignment to use Math.Min() or Math.Max() I have changed the methods
private int GetLowestItem(int[] items) { int lowestItem = Int32.MaxValue; foreach (int item in items) { // lowestItem = Math.Min(item, lowestItem); if (item < lowestItem) { lowestItem = item; } } return lowestItem; } private int GetHighestItem(int[] items) { int highestItem = Int32.MinValue; foreach (int item in items) { // highestItem = Math.Max(item, highestItem); if (item > highestItem) { highestItem = item; } } return highestItem; }
private int GetCountOfOccurance(int[] items, int comparingValue) { int count = 0; foreach (int item in items) { if (item == comparingValue) { count++; } } return count; }
private int GetHighestItemIndex(int[] items, int highestItem) { for(int i = 0 ; i<items.Length ; i++) { if(items[i] == highestItem) { return i; } } return -1; } private int GetLowestItemIndex(int[] items, int lowestItem) { // to be filled by you }
Next we should create a new calssed named BoundaryItem which holds the min and max values of the array.
class BoundaryItem { internal int Max { get; set; } internal int Min { get; set; } }
now we add a method to set each item of the array to zero if the value is either the max or the min of the array.
private void SetArrayitemsByValueToZero(int[] items, BoundaryItem boundaryItem) { for (int i = 0; i < items.Length; i++) { if (items[i] == boundaryItem.Min || items[i] == boundaryItem.Max) { items[i] = 0; } } }
Next we will add a 2 overloaded SumItems() methods
public int SumItems(int[] items) { BoundaryItem boundaryItem = PreProcessArray(items); return SumItems(items, boundaryItem); } private int SumItems(int[] items, BoundaryItem boundaryItem) { int sum = boundaryItem.Min + boundaryItem.Max; foreach (int item in items) { sum += item; } return sum; }
and last we add the missing PreProcessArray() method
private BoundaryItem PreProcessArray(int[] items) { BoundaryItem boundaryItem = new BoundaryItem(); boundaryItem.Min = GetLowestItem(items); boundaryItem.Max = GetHighestItem(items); int minOccurance = GetCountOfOccurance(items, boundaryItem.Min); int maxOccurance = GetCountOfOccurance(items, boundaryItem.Max); SetArrayitemsByValueToZero(items, boundaryItem); if (minOccurance < 2) { boundaryItem.Min = 0; } if (maxOccurance < 2) { boundaryItem.Max = 0; } return boundaryItem; }
But wait, we can still do better, if the amount of methods needed would not matter. Instead of GetLowestItem() and GetHighestItem() we create a method GetBoundaryItem()
private BoundaryItem GetBoundaryItem(int[] items) { BoundaryItem boundaryItem = new BoundaryItem(); boundaryItem.Min = Int32.MaxValue; boundaryItem.Max = Int32.MinValue; foreach (int item in items) { if (item < boundaryItem.Min) { boundaryItem.Min = item; } else if (item > boundaryItem.Max) { boundaryItem.Max = item; } } return boundaryItem; }
and change the PreProcessArray() method
private BoundaryItem PreProcessArray(int[] items) { BoundaryItem boundaryItem = GetBoundaryItem(items); int minOccurance = GetCountOfOccurance(items, boundaryItem.Min); int maxOccurance = GetCountOfOccurance(items, boundaryItem.Max); SetArrayitemsByValueToZero(items, boundaryItem); if (minOccurance < 2) { boundaryItem.Min = 0; } if (maxOccurance < 2) { boundaryItem.Max = 0; } return boundaryItem; }
The printing I will leave to you. As you see I have made instance methods out of the static methods. So it would be a good idea to create a class named Scoring where you place these methods.Then you would call this like
static void Main(string[] args) { Scoring scoring = new Scoring(); int[] scores = { 4, 8, 6, 4, 8, 5 }; int sum = scoring.SumItems(scores); // now print the result ExitProgram(); }
See: When to Use Static Classes in C#
As I have written the refactorings I came to the conclusion that we just need to get the index of the highest/lowest items so we can skip those items at composing the new array. After the coment from Malachi I realized that using the index of the highest/lowest item will be an invalid aproach if these values are contained more than 2 times in the array.
This implementation assumes that for the given array [1 ,1 ,1 ,2 ,3 ,3 ,3] it's sum should be 1 + 2 + 3 .
[4, 8, 4, 4, 8]\$\endgroup\$