Simple Selection Sort won't sort - c#

I'm new to algorithms and I tried to write a selection sort. With some help from the internet I have a script that should work, but doesn't. The result after the sort method is a list that is still unsorted.
I'm not sure if I missed anything and my code looks the same as the ones online.
Product.cs
public class Product
{
public string Name { get; set; }
public double Price { get; set; }
}
Order.cs
public class Order
{
public List<Product> listOfProducts = new List<Product>(){
new Product(){ Name="Item1", Price=2.55 },
new Product(){ Name="Item2", Price=1.92 },
new Product(){ Name="Item3", Price=2.12 }
};
public List<Product> GetAllProducts(){
return this.listOfProducts;
}
public void SortProductsByPrice(){
int min = 0;
for (int i = 0; i < this.listOfProducts.Count - 1; i++)
{
min = i;
for (int j = 0; j < this.listOfProducts.Count; j++)
{
if (listOfProducts[j].Price < listOfProducts[min].Price)
{
min = j;
}
}
Product temporary = listOfProducts[min];
listOfProducts[min] = listOfProducts[i];
listOfProducts[i] = temporary;
}
}
}
Program.cs
static void Main(string[] args)
{
Order order = new Order();
// unsorted list
foreach (Product pro in order.GetAllProducts())
{
Console.WriteLine(pro.Price);
}
Console.WriteLine("------------------------------------------");
order.SortProductsByPrice();
// sorted list
foreach (Product pro in order.GetAllProducts())
{
Console.WriteLine(pro.Price);
}
Console.ReadLine();
}

The problem in your code is in the nested loop.
If you take a closer look at the algorithm, you'll see that:
Selection sort is a simple sorting algorithm. This sorting algorithm is an in-place comparison-based algorithm in which the list is divided into two parts, the sorted part at the left end and the unsorted part at the right end. Initially, the sorted part is empty and the unsorted part is the entire list.
You're re-comparing your values with what you've already sorted, which you should not do. You're not getting a sorted list because by the end of your code, the values are being swapped over and over until they get back to their original order. A simple fix is by changing the nested for loop like this:
public void SortProductsByPrice()
{
int min = 0;
for (int i = 0; i < this.listOfProducts.Count - 1; i++)
{
min = i;
for (int j = i + 1; j < this.listOfProducts.Count; j++)
{
if (listOfProducts[j].Price < listOfProducts[min].Price)
{
min = j;
}
}
Product temporary = listOfProducts[min];
listOfProducts[min] = listOfProducts[i];
listOfProducts[i] = temporary;
}
}
So precisely, we just changed 1 line:
for (int j = i + 1; j < this.listOfProducts.Count; j++)
^^^^^
If you take another look at the pseudo-code in the above link, you'll see that this function now resembles it:
procedure selection sort
list : array of items
n : size of list
for i = 1 to n - 1
/* set current element as minimum*/
min = i
/* check the element to be minimum */
for j = i+1 to n
if list[j] < list[min] then
min = j;
end if
end for
/* swap the minimum element with the current element*/
if indexMin != i then
swap list[min] and list[i]
end if
end for
end procedure

Related

Sort an object T-shirt by the size property with bubble sort

Been tackling this all day now and I am really fed up with it. I am new to sorting and I was working on bubble sort, quick sort and finally a bucket sort for my school exercise.
Here is what I have for bucket sort for a list of Objects(T-shirts) sorted by Cost. Now T-shirts Have also Size, Fabric and Color and that is why I need to sort them as well. I know this falls in the sort strings by bubble sort category but I can not find anything about it and everything I tried went bad
public List<Tshirt> BucketSort(Tshirt[] array)
{
List<Tshirt> result = new List<Tshirt>();
// Determine how many buckets you want to create
//Create buckets
int numOfBuckets = 5;
List<Tshirt>[] buckets = new List<Tshirt>[numOfBuckets];
for (int i = 0; i < 5; i++)
buckets[i] = new List<Tshirt>();
//Iterate through the passed array and add each tshirt to the appropriate bucket
for (int i = 0; i < array.Length; i++)
{
int buckitChoice = ((int)array[i].Cost / numOfBuckets);
buckets[buckitChoice].Add(array[i]);
}
//Sort each bucket and add it to the result List
//Each sublist is sorted using Bubblesort, but you could substitute any sorting algo you would like
for (int i = 0; i < numOfBuckets; i++)
{
Tshirt[] temp = BubbleSortList(buckets[i]);
result.AddRange(temp);
}
return result;
}
public static Tshirt[] BubbleSortList(List<Tshirt> input)
{
for (int i = 0; i < input.Count; i++)
{
for (int j = 0; j < input.Count; j++)
{
if (input[i].Cost < input[j].Cost)
{
decimal temp = input[i].Cost;
input[i].Cost = input[j].Cost;
input[j].Cost = temp;
}
}
}
return input.ToArray();
}
public Tshirt[] ReturnContexttoArray()
{
var tshirts = _context.Tshirts;
Tshirt[] TshirtArr = new Tshirt[tshirts.Count()];
var count = 0;
foreach (var tshirt in tshirts)
{
TshirtArr[count++] = tshirt;
}
return TshirtArr;
}
public List<Tshirt> ImplementBucketSortAsc()
{
return BucketSort(ReturnContexttoArray());
}

Can you dynamically create variables based on rows in an Excel file in C#?

I am trying to make a C# program that takes coordinates from an excel file in the sense that each column is x,y,z and r, respectively, and each row is a different point. I would like to be able to create variables in the format point0, point1, etc. depending on how many rows there are.
As of right now I am reading each cell into an Array, then manually creating points from that array. In this case there are 4 rows and 4 points (points 0 to 3). This works for now but I have to imagine there is a much easier way of doing this or at least something more dynamic. 4 points is not a big deal but there could be many more.
int rows = 4;
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < rows; j++)
{
points[i,j] = excel.ReadCell(i, j);
}
}
for(int i = 0; i < 4; i++)
{
point0[0, i] = points[0, i];
}
for (int i = 0; i < 4; i++)
{
point1[1, i] = points[1, i];
}
for (int i = 0; i < 4; i++)
{
point2[2, i] = points[2, i];
}
for (int i = 0; i < 4; i++)
{
point3[3, i] = points[3, i];
}
Even condensing the set of loops where the points are manually created would save time, I am just not sure if there is a way to say something such as
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
point+"i"[i,j] = points[i,j]
}
}
Where the ith iteration is concatenated to the variable name.
Any help would be greatly appreciated, and I am open to all recommendations (I am pretty new to C# if you can't tell)
I would define a class of what the combination of the four points mean. Not based on the row or column that they're stored on but what they actually represent.
public class Shape
{
public int Start { get; set; }
public int End { get; set; }
public int Mean { get; set; }
public int Median { get; set; }
}
Then as you loop through each row you can Create and add all four points at the same time. Some thing like this.
public List GetShapesFromExcel()
{
var list = new List();
int StartColumn = 'x';
int EndColumn = 'y';
int MeanColumn = 'z';
int MedianColumn = 'r';
foreach (var row in workSheet)
{
var shape = new Shape()
{
Start = excel.ReadCell(row, StartColumn);
End = excel.ReadCell(row, EndColumn);
Mean = excel.ReadCell(row, MeanColumn);
Median = excel.ReadCell(row, MedianColumn);
};
}
return list;
}
I'm taking a wild stab in the dark on what you're data actually represents but I would take the time to go ahead and spin that up into a real object so that it's easier to reason about as you're writing the code.
variables like ā€˜Iā€™ & ā€˜Jā€™ Don't save enough time in this case to be useful.
last suggestion is to go ahead and check out the package EPPlus. that package has the ability to turn rows into structured classes
check this out to get started.
How to parse excel rows back to types using EPPlus

Trying to find Frequency of elements in array

I am trying to count how many times a number appears in an array 1 (a1) and then trying to print out that number by storing it in array 2 (a2) just once and then try to print array 2. But first using for loop and a function, I will check that if a number already exist in array 2 then move to next index in array 1, unfortunateley this code is not working; can someone please help me in trying to fix it, I don't need some complex solutions like dictionaries or lists athe moment, although it might be helpful too. thanks, I am not an expert in programming and I try to practise it in my free time, so please help me.
I just want this code to be fixed for my understanding and knowledge
class Program
{
static void Main(string[] args)
{
int i, j;
int[] a1 = new int[10];
int[] a2 = new int[10];
int[] a3 = new int[10];
//takes an input
for (i = 0; i < a1.Length; i++)
{
a1[i] = Convert.ToInt32(Console.ReadLine());
}
for (i = 0; i < a1.Length; i++)
{
Cn(a1, a2); //calls in function
i++; //increments is if true
int count = 0;
for (j = 0; j < a1.Length; j++)
{
//if a number matches with a number in second array
if (a1[i] == a1[j])
{
//do count ++
count++;
// store that number into second array
a2[i] = a1[i];
}
}
//store the number of counts in third array
a3[i] = count;
}
for (i = 0; i < a2.Length; i++)
{
if (a2[i] != 0)
{
Console.WriteLine(a2[i]);
}
}
Console.ReadLine();
}
//function to check if element at current index of array 1 exists in array 2 if yes than break
public static void Cn (int[] aa1, int [] aa2)
{
int k, j;
for ( k = 0; k < aa1.Length; k++)
{
for (j = 0; j < aa2.Length; j++)
{
if (aa1[k] == aa2[j])
break;
}
}
}
}
You probably want to do a group by count:
int[] a1 = new int[10];
var rnd = new Random();
//takes an input
for (int i = 0; i < a1.Length; i++)
{
a1[i] = Convert.ToInt32(rnd.Next(0, 11)); // or Console.ReadLine()
}
var grouped = a1
.GroupBy(x => x)
.Select(g => new
{
Item = g.Key,
Count = g.Count()
}).ToList(); // ToList() is optional, materializes the IEnumerable
foreach (var item in grouped)
{
Console.WriteLine($"number: {item.Item}, count: {item.Count}");
}
This uses a Hash algorithm internally.
You can solve this without a Hash or Dictionary but it wouldn't be very efficient because you need to do lots of linear searches through the arrays.
The advantage of a Hash algorithm is that your lookups or groupings are much faster than if you loop over a complete array to find / increment an item.

How is my boundaries outside of the array?

On my array, on line 40, my boundaries are outside of the array, but I am not sure how to format this since this is my first program with a multi dimensional array. Please help me. Thanks! (Line 40 is array[i, 0] = randomArray.Next(0, 100);)
namespace Exercise6
{
class Program
{
static void Main(string[] args)
{
OtherClass aTable = new OtherClass(); //instantiate class
Console.WriteLine("How many rows do you want your two-dimensional array to be?");
aTable.SRows = Console.ReadLine(); //reads input for how many rows that the user would like
aTable.IntRows = int.Parse(aTable.SRows); //convert rows to int
Console.WriteLine("Thanks you! How many columns would you like your two-dimensional arry to be?");
aTable.SColumns = Console.ReadLine(); //reads input for how many columns that the user would like
aTable.IntColumns = int.Parse(aTable.SColumns); //convert columns to int
//set two dimensional array based upon the size that the user has requested
int[ , ] array = new int[aTable.IntColumns, aTable.IntRows];
Random randomArray = new Random(); //call to random class to ask for random numbers
for (int i = 0; i <= aTable.IntColumns; i++) // rows
{
array[i, 0] = randomArray.Next(0, 100); // for every value in each row, insert a random number
}
//both arrays here are overloaded. See this site to see if can get help. Site is below after last close loop
for (int y = 0; y <= aTable.IntRows; y++) // columns
{
array[y, y] = randomArray.Next(0, 100);
}
Console.WriteLine(array);
}
}
}
namespace Exercise6
{
class OtherClass
{
private string sRows;
public string SRows { get; set; }
private int intRows;
public int IntRows { get; set; }
private string sColumns;
public string SColumns { get; set; }
private int intColumns;
public int IntColumns { get; set; }
}
}
Change loop condition to i < aTable.IntColumns
You loop starts from 0 and goes to value of aTable.IntColumns - 1
and code becomes
for (int i = 0; i < aTable.IntColumns; i++)
{
array[i, 0] = randomArray.Next(0, 100);
}
Since arrays are zero based, you can't go up to the max value:
// This line is incorrect
for (int i = 0; i <= aTable.IntColumns; i++)
That line should be:
for (int i = 0; i < aTable.IntColumns; i++)
That will let it go from 0 to aTable.IntColumns-1, which are the valid indices for for an array of aTable.IntColumns length. The same is true of the rows.
C# arrays used zero-relative offsets as their indices. That means that for an array of length n, the domain of its index i is 0 <= i <= n-1. A 100-element array has an index that ranges from 0-99. If you are trying to fill an m*n array with random values.
If your assignment is fill the array with random values (as seems likely), you'll need to do something like this:
for ( int i=0 ; i < aTable.IntRows ; i++ ) // rows
{
for ( int j= 0 ; i < aTable.IntColumns ; j++ )
{
array[i,j] = randomArray.Next(0,100); // for every value in each row, insert a random number
}
}
You might also note that your comments don't match your code: you are iterating over rows and checking the column limit and vice-versa.
The error is in for loop:
for (int i = 0; i < aTable.IntColumns; i++) // rows
{
array[i, 0] = randomArray.Next(0, 100); // for every value in each row, insert a random number
}
i < aTable.IntColumns should be the stopping criteria

Forming a tournament table with LINQ (Fixture List)

I have an array of players (string[]) and now I need to get an array of pairs representing games (playerN-playerM) to orginize tournament table like at this picture:
The desired end result is to generate a fixture list with all the games the need to be played.
How can I do this with LINQ in efficient way?
UPDATED:
A-B, A-C, A-D is not correct - games should be able to run in parallel.
I need result in the same order as at the picture
The following code can be used to generate a fixture list for a collection of teams to ensure that each time plays all other teams in 1 home and 1 away match.
The code is a bit long winded but it does work by providing you with a list in the order you have specified.
The code can probably be optimised but at the moment this is how it has come from my head.
NOTE: The resulting list will contain both Home and Away fixture, which based on your grid will be what you need to do anyway.
class Fixture
{
public string Home { get; set; }
public string Away { get; set; }
}
void CallCode()
{
string players = new string[] { "A", "B", "C", "D" };
List<Fixture> fixtures = CalculateFixtures(players);
}
List<Fixture> CalculateFixtures(string[] players)
{
//create a list of all possible fixtures (order not important)
List<Fixture> fixtures = new List<Fixture>();
for (int i = 0; i < players.Length; i++)
{
for (int j = 0; j < players.Length; j++)
{
if (players[i] != players[j])
{
fixtures.Add(new Fixture() { Home = players[i], Away = players[j] });
}
}
}
fixtures.Reverse();//reverse the fixture list as we are going to remove element from this and will therefore have to start at the end
//calculate the number of game weeks and the number of games per week
int gameweeks = (players.Length - 1) * 2;
int gamesPerWeek = gameweeks / 2;
List<Fixture> sortedFixtures = new List<Fixture>();
//foreach game week get all available fixture for that week and add to sorted list
for (int i = 0; i < gameweeks; i++)
{
sortedFixtures.AddRange(TakeUnique(fixtures, gamesPerWeek));
}
return sortedFixtures;
}
List<Fixture> TakeUnique(List<Fixture> fixtures, int gamesPerWeek)
{
List<Fixture> result = new List<Fixture>();
//pull enough fixture to cater for the number of game to play
for (int i = 0; i < gamesPerWeek; i++)
{
//loop all fixture to find an unused set of teams
for (int j = fixtures.Count - 1; j >= 0; j--)
{
//check to see if any teams in current fixtue have already been used this game week and ignore if they have
if (!result.Any(r => r.Home == fixtures[j].Home || r.Away == fixtures[j].Home || r.Home == fixtures[j].Away || r.Away == fixtures[j].Away))
{
//teams not yet used
result.Add(fixtures[j]);
fixtures.RemoveAt(j);
}
}
}
return result;
}
var games = players.SelectMany((player1, index) =>
players.Skip(index + 1).
Select(player2 => new {Player1 = player1, Player2 = player2}));
That should do it...
The implementation I really wanted:
public static List<List<Tuple<string, string>>> ListMatches(List<string> listTeam)
{
var result = new List<List<Tuple<string, string>>>();
int numDays = (listTeam.Count - 1);
int halfSize = listTeam.Count / 2;
var teams = new List<string>();
teams.AddRange(listTeam.Skip(halfSize).Take(halfSize));
teams.AddRange(listTeam.Skip(1).Take(halfSize - 1).ToArray().Reverse());
int teamsSize = teams.Count;
for (int day = 0; day < numDays; day++)
{
var round = new List<Tuple<string, string>>();
int teamIdx = day % teamsSize;
round.Add(new Tuple<string, string>(teams[teamIdx], listTeam[0]));
for (int idx = 1; idx < halfSize; idx++)
{
int firstTeam = (day + idx) % teamsSize;
int secondTeam = (day + teamsSize - idx) % teamsSize;
round.Add(new Tuple<string, string>(teams[firstTeam], teams[secondTeam]));
}
result.Add(round);
}
return result;
}

Categories

Resources