Solution: Had multiple calls to the method and therefore had more called remove more times, than items were existing.
In my programm I need to remove Items out of a List. But once I get to the RemoveAt() command, I get an ArgumentOutOfRangeException and it tells me that all of my Lists have a count of 0, or in other words, are empty. But though it says they are empty, the object were created and all of the methods and events are working just fine. Here's some parts of my code:
My Lists:
measure = new List<Messen>(maxAblaufe);
steuern = new List<Steuern>(maxAblaufe);
model = new List<Model>(maxAblaufe);
measureReflector = new List<EventReflector>(maxAblaufe);
steuernReflector = new List<EventReflector>(maxAblaufe);
Creating the Lists:
if (nextSet < maxAblaufe)
{
neuerAblauf na = new neuerAblauf();
na.Show();
//if (model.Count == nextSet)
model.Add(new Model());
na.Model = model.ElementAt(nextSet);
model.ElementAt(nextSet).Index = nextSet;
na.eventStartAblauf += this.startAblauf;
}
And:
public void startAblauf(object sender, EventArgs e) {
EventReflector ers = new EventReflector();
EventReflector erm = new EventReflector();
steuernReflector.Add(ers);
measureReflector.Add(erm);
if (nextSet > 0)
{
measure.ElementAt(nextSet-1).eventNextMeasure += measureReflector.ElementAt(nextSet).reflectEvent;
steuern.ElementAt(nextSet-1).eventNextSteuern += steuernReflector.ElementAt(nextSet).reflectEvent;
}
else if (nextSet == 0) {
timingMessen.eventRefreshData += measureReflector.ElementAt(nextSet).reflectEvent;
timingSteuerung.eventRefreshSteuerung += steuernReflector.ElementAt(nextSet).reflectEvent;
}
model.ElementAt(nextSet).MesstabellePath = "C:\\Users\\myuser\\Documents\\Privat\\MessTest\\Messung" + nextSet + ".csv";
Messen mess = new Messen(model.ElementAt(nextSet), myPLC, 60 + nextSet * 20, measureReflector.ElementAt(nextSet));
measure.Add(mess);
Steuern str = new Steuern(model.ElementAt(nextSet), steuertakt, myPLC, 60 + nextSet * 20, mess, steuernReflector.ElementAt(nextSet));
steuern.Add(str);
steuern.ElementAt(nextSet).eventDisconnectAblauf += this.disconnectAblauf;
nextSet++;
}
The part where I (try) to delete the items is this:
public void disconnectAblauf(object sender, EventArgs e) {
SteuernArgs es = (SteuernArgs)e;
int index = es.index;
int indexbefore = index;
indexbefore--;
int indexafter = index;
indexafter++;
if (index > 0 && nextSet > (indexafter))
{
measure.ElementAt(indexbefore).eventNextMeasure += measureReflector.ElementAt(indexafter).reflectEvent;
steuern.ElementAt(indexbefore).eventNextSteuern += steuernReflector.ElementAt(indexafter).reflectEvent;
}
else if (index == 0 && nextSet > (indexafter)) {
timingMessen.eventRefreshData += measureReflector.ElementAt(indexafter).reflectEvent;
timingMessen.eventRefreshData -= measureReflector.ElementAt(index).reflectEvent;
timingSteuerung.eventRefreshSteuerung += steuernReflector.ElementAt(indexafter).reflectEvent;
timingSteuerung.eventRefreshSteuerung -= steuernReflector.ElementAt(index).reflectEvent;
}
steuernReflector.RemoveAt(index);
steuern.RemoveAt(index);
measure.RemoveAt(index);
measureReflector.RemoveAt(index);
model.RemoveAt(index);
I already tried a lot of things so there may be some commented lines or "useless" lines, just try to ignore those, thanks!
EDIT:
Trimmed Version of the (in my opinion) relevent code:
measure = new List<Messen>(maxAblaufe);
steuern = new List<Steuern>(maxAblaufe);
model = new List<Model>(maxAblaufe);
measureReflector = new List<EventReflector>(maxAblaufe);
steuernReflector = new List<EventReflector>(maxAblaufe);
EventReflector ers = new EventReflector();
EventReflector erm = new EventReflector();
steuernReflector.Add(ers);
measureReflector.Add(erm);
model.ElementAt(nextSet).MesstabellePath = "C:\\Users\\myuser\\Documents\\Privat\\MessTest\\Messung" + nextSet + ".csv";
Messen mess = new Messen(model.ElementAt(nextSet), myPLC, 60 + nextSet * 20, measureReflector.ElementAt(nextSet));
measure.Add(mess);
Steuern str = new Steuern(model.ElementAt(nextSet), steuertakt, myPLC, 60 + nextSet * 20, mess, steuernReflector.ElementAt(nextSet));
steuern.Add(str);
steuernReflector.RemoveAt(index);
steuern.RemoveAt(index);
measure.RemoveAt(index);
measureReflector.RemoveAt(index);
model.RemoveAt(index);
I think the problem is that you are storing the index in the Index property. Suppose you have three items in the collection, and first you remove the one with index 0. This will shorten the List and item with Index property of 2 will move to index 1. This however means that if you now run the remove method, the item will no longer be on the position 2 and the attempt to access it will throw ArgumentOutOfRangeException.
Related
I have a working code that has to many lines of repeated code. I would like to write a method to save lines of code.
I have a query that gets the number of registries in the database. The number of registries may vary from 1 to 20. The number of registries is saved in the decimal numberOfLines.
Today I am using 20 if's, that writes 4 textboxes per line for each possible number of lines I have.
If I have only one line it write 1 line of 4 textboxes, if I have 2 lines it writes 2 lines of 4 textboxes and so one.
I will only show the code for the quantity of lines from 1 to 4 just to save space (the rest of the code is just copy/paste and change the textboxes new indexes).
//write the lines according to the number of lines
if (numberOfLines == 1)
{
txt_A1.Text = tableAs.Rows[0][0].ToString();
txt_B1.Text = tableAs.Rows[0][1].ToString();
txt_C1.Text = tableAs.Rows[0][2].ToString();
txt_D1.Text = tableAs.Rows[0][3].ToString();
}
if (numberOfLines ==2)
{
txt_A1.Text = tableAs.Rows[0][0].ToString();
txt_B1.Text = tableAs.Rows[0][1].ToString();
txt_C1.Text = tableAs.Rows[0][2].ToString();
txt_D1.Text = tableAs.Rows[0][3].ToString();
txt_A2.Text = tableAs.Rows[1][0].ToString();
txt_B2.Text = tableAs.Rows[1][1].ToString();
txt_C2.Text = tableAs.Rows[1][2].ToString();
txt_D2.Text = tableAs.Rows[1][3].ToString();
}
if (numberOfLines == 3)
{
txt_A1.Text = tableAs.Rows[0][0].ToString();
txt_B1.Text = tableAs.Rows[0][1].ToString();
txt_C1.Text = tableAs.Rows[0][2].ToString();
txt_D1.Text = tableAs.Rows[0][3].ToString();
txt_A2.Text = tableAs.Rows[1][0].ToString();
txt_B2.Text = tableAs.Rows[1][1].ToString();
txt_C2.Text = tableAs.Rows[1][2].ToString();
txt_D2.Text = tableAs.Rows[1][3].ToString();
txt_A3.Text = tableAs.Rows[2][0].ToString();
txt_B3.Text = tableAs.Rows[2][1].ToString();
txt_C3.Text = tableAs.Rows[2][2].ToString();
txt_D3.Text = tableAs.Rows[2][3].ToString();
}
if (numberOfLines == 4)
{
txt_A1.Text = tableAs.Rows[0][0].ToString();
txt_B1.Text = tableAs.Rows[0][1].ToString();
txt_C1.Text = tableAs.Rows[0][2].ToString();
txt_D1.Text = tableAs.Rows[0][3].ToString();
txt_A2.Text = tableAs.Rows[1][0].ToString();
txt_B2.Text = tableAs.Rows[1][1].ToString();
txt_C2.Text = tableAs.Rows[1][2].ToString();
txt_D2.Text = tableAs.Rows[1][3].ToString();
txt_A3.Text = tableAs.Rows[2][0].ToString();
txt_B3.Text = tableAs.Rows[2][1].ToString();
txt_C3.Text = tableAs.Rows[2][2].ToString();
txt_D3.Text = tableAs.Rows[2][3].ToString();
txt_A4.Text = tableAs.Rows[3][0].ToString();
txt_B4.Text = tableAs.Rows[3][1].ToString();
txt_C4.Text = tableAs.Rows[3][2].ToString();
txt_D4.Text = tableAs.Rows[3][3].ToString();
}
With the amount of possible lines I have (20) the code gets very big, and not as beautiful as I expected (with the use of a method for example).
I write a method that you could create textboxes according to the line.
Code:
private void button1_Click(object sender, EventArgs e)
{
int a = Convert.ToInt32(richTextBox1.Text);
CreateTextbox(a);
}
public void CreateTextbox(int line)
{
int count = 0;
int num = 0;
for (int i = 0; i < line*4; i++)
{
TextBox box = new TextBox();
box.Name = "A" + i.ToString();
if (count >= 4)
{
count = 0;
num++;
}
box.Location = new Point(count*(box.Width+20),num*40);
count++;
this.Controls.Add(box);
}
}
}
Try this refactoring:
var items = new Dictionary<int, List<TextBox>>()
{
{ 1, new List<TextBox>() { txt_A1, txt_B1, txt_C1, txt_D1 } },
{ 2, new List<TextBox>() { txt_A1, txt_B1, txt_C1, txt_D1, txt_A2, txt_B2, txt_C2, txt_D2 } },
{ 3, new List<TextBox>() { txt_A1, txt_B1, txt_C1, txt_D1, txt_A2, txt_B2, txt_C2, txt_D2, txt_A3, txt_B3, txt_C3, txt_D3 } },
{ 4, new List<TextBox>() { txt_A1, txt_B1, txt_C1, txt_D1, txt_A2, txt_B2, txt_C2, txt_D2, txt_A3, txt_B3, txt_C3, txt_D3, txt_A4, txt_B4, txt_C4, txt_D4 } }
};
int index1 = 0;
int index2 = 0;
foreach ( var item in items[numberOfLines] )
{
item.Text = tableAs.Rows[index1][index2].ToString();
if ( ++index2 > 3 )
{
index2 = 0;
index1++;
}
}
I am creating an app that measures the time a person has gazed at around 300 objects. For all of the objects, it needs to output the time into a text file. I've succesfully coded this for just one object, but I am trying to do it for 300 objects. This is the code I have created for one object:
Stopwatch Timer = new Stopwatch();
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
TimeSpan Word1 = TimeSpan.Zero;
gazeButtonControl1.StateChanged += GazeBlockControl1_StateChanged;
void GazeBlockControl1_StateChanged(object sender, StateChangedEventArgs ea)
{
if (ea.PointerState == PointerState.Enter)
{
Timer.Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer.Stop();
Word1 += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word1.ToString());
Timer.Reset();
}
}
Everytime there is a "1" inserted in the variable or name of an element, I want to have that for all of the 300 objects. This is what I am looking for:
Stopwatch Timer = new Stopwatch();
for (int i = 0; i < 300; i++) {
gazeButtonControl[i] = GazeInput.GetGazeElement(GazeBlock[i]);
gazeButtonControl[i] = new GazeElement();
GazeInput.SetGazeElement(GazeBlock[i], gazeButtonControl[i]);
TimeSpan Word[i] = TimeSpan.Zero;
gazeButtonControl[i].StateChanged += GazeBlockControl[i]_StateChanged;
void GazeBlockControl[i]_StateChanged(object sender, StateChangedEventArgs ea)
{
if (ea.PointerState == PointerState.Enter)
{
Timer.Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer.Stop();
Woord[i] += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word[i].ToString());
Timer.Reset();
}
}
}
This code doesn't work. I've tried using lists and that didn't work either. Does anyone know how to make this solution work? Thanks in advance!
Vincent
You can't use placeholders or array indices in names of variables, methods, and so on.
For UWP there seems to be a helper method FindChildByName which allows you to find a control by its name, via (TypeOfChildControl)insertParentControlHere.FindChildByName("<Name of child control>").
I find the following code of yours perplexing:
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
Basically, first you get your gazeButtonControl1 from GazeBlock1 and then ignore it to create a new GazeElement. I guess what is meant is something like in this UWP Gaze sample where it's first checked if the UI control has a gaze element and if not one is created. So I think it should be:
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
if (gazeButtonControl1 == null)
{
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
}
Also like i wrote in my initial comment you probably need a separate timer for each gaze element.
So in total it should be something like this (albeit untested):
public class YourClass
{
private TimeSpan[] Word = new TimeSpan[300];
private Stopwatch[] Timer = new Stopwatch[300];
private GazeElement[] gazeButtonControl = new GazeElement[300];
public YourMethod(...)
{
for (int i = 0; i < 300; i++)
{
// first find gaze block where parentControl is the control containing your gaze blocks.
var gazeBlock = (UIElement)parentControl.FindChildByName("GazeBlock" + (i + 1));
gazeButtonControl[i] = GazeInput.GetGazeElement(gazeBlock);
if (gazeButtonControl[i] == null)
{
gazeButtonControl[i] = new GazeElement();
GazeInput.SetGazeElement(gazeBlock, gazeButtonControl[i]);
}
Word[i] = TimeSpan.Zero;
Timer[i] = new Stopwatch();
gazeButtonControl[i].StateChanged += GazeBlockControl_StateChanged;
}
}
private void GazeBlockControl_StateChanged(object sender, StateChangedEventArgs ea)
{
// get the GazeElement for which this event was raised
var changedControl = (GazeElement)sender;
// find its index in your list of GazeElements.
var i = Array.IndexOf(gazeButtonControl, changedControl);
if (ea.PointerState == PointerState.Enter)
{
Timer[i].Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer[i].Stop();
Word[i] += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word[i].ToString());
Timer[i].Reset();
}
}
}
Please not that I use Array.IndexOf instead of gazeButtonControl.IndexOf because I declared gazeButtonControl as an array. If it would be a list (e.g. List<GazeElement> gazeButtonControl) you would use gazeButtonControl.IndexOf.
I've got a list of Players. Each Player has a Marketvalue. I need to build up a second list which iterates through the player list and builds up a team. The tricky thing is the new team should have at least 15 players and a maximum Marketvalue of 100 Mio +/- 1%.
Does anyone know how to do that elegantly?
private Result<List<Player>> CreateRandomTeam(List<Player> players, int startTeamValue)
{
// start formation 4-4-2
// Threshold tw 20 mio defender 40 mio Midfielder 40 Mio Striker 50 Mio
var playerKeeperList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Keeper);
var playerDefenderList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Defender);
var playerMidfieldList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Midfield);
var playerStrikerList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Striker);
List<Player> keeperPlayers = AddRandomPlayers(playerKeeperList, 2, 0, 20000000);
List<Player> defenderPlayers = AddRandomPlayers(playerDefenderList, 4, 0, 40000000);
List<Player> midfieldPlayers = AddRandomPlayers(playerMidfieldList, 4, 0, 40000000);
List<Player> strikerPlayers = AddRandomPlayers(playerStrikerList, 2, 0, 50000000);
List<Player> team = new List<Player>();
team.AddRange(keeperPlayers);
team.AddRange(defenderPlayers);
team.AddRange(midfieldPlayers);
team.AddRange(strikerPlayers);
var currentTeamValue = team.Sum(s => s.MarketValue);
var budgetLeft = startTeamValue - currentTeamValue;
players.RemoveAll(p => team.Contains(p));
var player1 = AddRandomPlayers(players, 2, 0, budgetLeft);
team.AddRange(player1);
players.RemoveAll(p => player1.Contains(p));
currentTeamValue = team.Sum(t => t.MarketValue);
budgetLeft = startTeamValue - currentTeamValue;
var player2 = players.Aggregate((x, y) => Math.Abs(x.MarketValue - budgetLeft) < Math.Abs(y.MarketValue - budgetLeft) ? x : y);
team.Add(player2);
players.Remove(player2);
return Result<List<Player>>.Ok(team);
}
private static List<Player> AddRandomPlayers(List<Player> players, int playerCount, double minMarketValue, double threshold)
{
// TODO: AYI Implement Random TeamName assign logic
Random rnd = new Random();
var team = new List<Player>();
double assignedTeamValue = 0;
while (team.Count < playerCount)
{
var index = rnd.Next(players.Count);
var player = players[index];
if ((assignedTeamValue + player.MarketValue) <= threshold)
{
team.Add(player);
players.RemoveAt(index);
assignedTeamValue += player.MarketValue;
}
}
return team;
}`
This isn't really a C# question so much as an algorithm question, so there may be a better place for it. AIUI, you want to pick 15 numbers from a list, such that the total adds up to 99-101.
It's likely that there are many solutions, all equally valid.
I think you could do it like this:
Build a list of the 14 cheapest items.
Pick the highest value, so long as the remaining space is greater than the total of the 14 cheapest.
Repeat the above, skipping any players that won't fit.
Fill the remaining places with players from the 'cheapest' list.
This will probably give you a team containing the best and worst players, and one middle-ranking player that just fits.
If you want to do some more research, this sounds like a variant of the coin change problem.
Just to show my solution if someone need's it.
var selection = new EliteSelection();
var crossover = new OnePointCrossover(0);
var mutation = new UniformMutation(true);
var fitness = new TeamFitness(players, startTeamValue);
var chromosome = new TeamChromosome(15, players.Count);
var population = new Population(players.Count, players.Count, chromosome);
var ga = new GeneticAlgorithm(population, fitness, selection, crossover, mutation)
{
Termination = new GenerationNumberTermination(100)
};
ga.Start();
var bestChromosome = ga.BestChromosome as TeamChromosome;
var team = new List<Player>();
if (bestChromosome != null)
{
for (int i = 0; i < bestChromosome.Length; i++)
{
team.Add(players[(int) bestChromosome.GetGene(i).Value]);
}
// Remove assigned player to avoid duplicate assignment
players.RemoveAll(p => team.Contains(p));
return Result<List<Player>>.Ok(team);
}
return Result<List<Player>>.Error("Chromosome was null!");
There is a fitness method which handles the logic to get the best result.
class TeamFitness : IFitness
{
private readonly List<Player> _players;
private readonly int _startTeamValue;
private List<Player> _selected;
public TeamFitness(List<Player> players, int startTeamValue)
{
_players = players;
_startTeamValue = startTeamValue;
}
public double Evaluate(IChromosome chromosome)
{
double f1 = 9;
_selected = new List<Player>();
var indexes = new List<int>();
foreach (var gene in chromosome.GetGenes())
{
indexes.Add((int)gene.Value);
_selected.Add(_players[(int)gene.Value]);
}
if (indexes.Distinct().Count() < chromosome.Length)
{
return int.MinValue;
}
var sumMarketValue = _selected.Sum(s => s.MarketValue);
var targetValue = _startTeamValue;
if (sumMarketValue < targetValue)
{
f1 = targetValue - sumMarketValue;
}else if (sumMarketValue > targetValue)
{
f1 = sumMarketValue - targetValue;
}
else
{
f1 = 0;
}
var keeperCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Keeper);
var strikerCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Striker);
var defCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Defender);
var middleCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Midfield);
var factor = 0;
var penaltyMoney = 10000000;
if (keeperCount > 2)
{
factor += (keeperCount - 2) * penaltyMoney;
}
if (keeperCount == 0)
{
factor += penaltyMoney;
}
if (strikerCount < 2)
{
factor += (2 - strikerCount) * penaltyMoney;
}
if (middleCount < 4)
{
factor += (4 - middleCount) * penaltyMoney;
}
if (defCount < 4)
{
factor += (4 - defCount) * penaltyMoney;
}
return 1.0 - (f1 + factor);
}
}
I am working with a link list. I have set my constructor to take an array named ax with a set of already defined items. I also decided to have an input box which through a BtnAddTree_Click appends the new item to the list ax. But instead of appending to the list ax it creates a whole new separate list. How can I append items to the array list ax through my AddTree function?
public ListForTrees(IEnumerable<fruit_trees> trees)
{
foreach (fruit_trees t in trees)
{
this.AddTree(t);
}
}
public void AddTree(fruit_trees new_tree)
{
fruit_trees current = first_tree;
if (count == 0)
{
first_tree = new_tree;
last_tree = new_tree;
count = 1;
}
else if (count != 0)
{
if (new_tree.tree_price <= first_tree.tree_price)
{
new_tree.next_tree = first_tree;
first_tree = new_tree;
}
else if (new_tree.tree_price >= last_tree.tree_price)
{
last_tree.next_tree = new_tree;
last_tree = new_tree;
}
else
{
while (new_tree.tree_price > current.next_tree.tree_price)
{
current = current.next_tree;
}
new_tree.next_tree = current.next_tree;
current.next_tree = new_tree;
}
count++;
}
}
}
ListForTrees mainlist = new ListForTrees();
private void BtnGo_Click(object sender, EventArgs e)
{
fruit_trees[] ax = { new fruit_trees("cherry", 48, 12.95, 3),
new fruit_trees("pine", 36, 9.95, 8),
new fruit_trees("oak", 60, 14.95, 2),
new fruit_trees("peach", 54, 19.95, 3),
new fruit_trees("pear", 36, 11.85, 2),
new fruit_trees("apple", 62, 13.45, 5)
};
mainlist = new ListForTrees(ax);
fruit_trees current = mainlist.first_tree;
while (current != null)
{
current = current.next_tree;
}
}
}
}
It doesn't seem to be creating a new separate list. I tested out the following code with yours:
public class TreeTester
{
public static void Main(string[] args)
{
var list = new ListForTrees(
new[] { new fruit_trees("tree10",10,10,10), new fruit_trees("tree2",2,2,2) });
list.AddTree( new fruit_trees("tree3",3,3,3) ); // middle
list.AddTree( new fruit_trees("tree1",1,1,1) ); // first
list.AddTree( new fruit_trees("tree50",50,50,50) ); // last
list.AddTree( new fruit_trees("tree5",5,5,5) ); // middle
Console.Write(list);
}
}
And got the following output, which seems correct.
tree1 1 1 1
tree2 2 2 2
tree3 3 3 3
tree5 5 5 5
tree10 10 10 10
tree50 50 50 50
What is the expected behavior, if this is not correct? Clearly these items are all being added to the original list, since they're present when I iterate through the list.
By the way, I also added the following ToString function to your ListForTrees class; it makes debugging easier.
public override string ToString()
{
string s = "";
for (var tree=first_tree; tree!=null; tree = tree.next_tree)
s += tree + "\n";
return s;
}
Edit: I must comment that you may find it helpful to cleanup your code a bit in trying to understand where it is going wrong. For example, your ListForTrees(fruit_trees new_tree) constructor does the same exact thing as calling Add(new_tree) would. Also, think about three cases you have in Add, under else if (count != 0) -- perhaps there's a way they could elegantly combined into one general while loop? It makes it easier to analyze, and (potentially) less error-prone.
I am using the Knuth-Fisher-Yates algorithm to display a shuffled array of string items on a windows form. I do not get any duplicates, which is what I was trying to achieve, however, it only spits out 12 of the 13 elements of the array. How can I get it to display all 13 elements of the array? Here is my code:
private void FormBlue1_Load(object sender, EventArgs e)
{
// set the forms borderstyle
this.FormBorderStyle = FormBorderStyle.Fixed3D;
// create array of stationOneParts to display on form
string[] stationOneParts = new string[13];
stationOneParts[0] = "20-packing";
stationOneParts[1] = "5269-stempad";
stationOneParts[2] = "5112-freeze plug";
stationOneParts[3] = "2644-o'ring";
stationOneParts[4] = "5347-stem";
stationOneParts[5] = "4350-top packing";
stationOneParts[6] = "5084-3n1 body";
stationOneParts[7] = "4472-packing washer";
stationOneParts[8] = "3744-vr valve o'ring";
stationOneParts[9] = "2061-packing spring";
stationOneParts[10] = "2037-packing nut";
stationOneParts[11] = "2015-latch ring";
stationOneParts[12] = "stem assembly";
Random parts = new Random();
// loop through stationOneParts using a Swap method to shuffle
labelBlueOne.Text = "\n";
for (int i = stationOneParts.Length - 1; i > 0; i--)
{
int j = parts.Next(i + 1);
Swap(ref stationOneParts[i], ref stationOneParts[j]);
// display in a random order
labelBlueOne.Text += stationOneParts[i] + "\n";
}
}
private void Swap(ref string firstElement, ref string secondElement)
{
string temp = firstElement;
firstElement = secondElement;
secondElement = temp;
}
You don't access the first element.
for (int i = stationOneParts.Length - 1; i >= 0; i--).
As you are showing the texts using the loop that swaps the items, you will not show the last item, because it's never swapped by itself.
Just show the last item after the loop:
labelBlueOne.Text += stationOneParts[0] + "\n";
Alternatively, you can display all the items outside the loop that shuffles them:
for (int i = stationOneParts.Length - 1; i > 0; i--) {
Swap(ref stationOneParts[i], ref stationOneParts[parts.Next(i + 1)]);
}
labelBlueOne.Text = "\n" + String.Join("\n", stationOneParts);
Change your loop condition to i >= 0.
Simpliest approach :
Random rnd = new Random();
var stationOneParts = new List<string>{
"20-packing",
"5269-stempad",
"5112-freeze plug",
"2644-o'ring",
"5347-stem",
"4350-top packing",
"5084-3n1 body",
"4472-packing washer",
"3744-vr valve o'ring",
"2061-packing spring",
"2037-packing nut",
"2015-latch ring",
"stem assembly"}.OrderBy(s => rnd.Next());
labelBlueOne.Text = string.Join(Environment.NewLine, stationOneParts);
Since you mention C# 4.0, why not write is C#-ish?
using System.Linq;
// ...
var stationOneParts = new [] { "20-packing",
"5269-stempad",
"5112-freeze plug",
"2644-o'ring",
"5347-stem",
"4350-top packing",
"5084-3n1 body",
"4472-packing washer",
"3744-vr valve o'ring",
"2061-packing spring",
"2037-packing nut",
"2015-latch ring",
"stem assembly" };
Random rand = new Random();
stationOneParts = stationOneParts
.Distinct() // see subject: '... without duplicates'
.Select(i => new { i, key=rand.Next() })
.OrderBy(p => p.key)
.Select(p => p.i)
.ToArray();