Objects in List<T> reference same value - c#

I have a list of custom objects List<Slot>
Each Object Slot has an array of Gene[]
Object slot
public class Slot
{
private Gene[] _genes;
private int _fitness;
//...
public Slot(int count)
{
_genes = InitializeArray<Gene>(count);
Fitness = 0;
}
public Gene[] getChromosomes()
{
return Genes; //getter method
}
//Helper to init array
static T[] InitializeArray<T>(int length) where T : new()
{
T[] array = new T[length];
for (int i = 0; i < length; ++i)
{
array[i] = new T();
}
return array;
}
}
Object Gene
public class Gene
{
private DateTime _date;
private int _tcode;
private byte _availabe;
private byte _duty;
private int _fitness;
//...
public Gene()
{
_fitness = 0;
}
}
Main
private List<Slot> slotsList = new List<Slot>();
//...
//...
private void init_population(int lchromeSize, int lpopulationSize)
{
slotsList.Clear();
Gene[] lstGene = InitializeArray<Gene>(lchromeSize);
//For all slots
for (int i = 0; i < tempInt; i++)
{
//for all genes
for (int ii = 0; ii < lchromeSize; ii++)
{
//assign values to local variables
// and :
lstGene[ii].Date = ldate;
lstGene[ii].Tcode = lteacherCode;
lstGene[ii].Availabe = lavailable;
lstGene[ii].Duty = tempDuty;
lstGene[ii].Fitness = 0;
}
//End ii For
//Add the genes to slotsList
Slot itemtoadd = new Slot(lchromeSize);
itemtoadd.setChromosomes(lstGene);
slotsList.Add(itemtoadd);
}
}
The problem is that in every single Slot the Genes are identical and they reference the last lstGene[] that has been added to slotsList.
Where did I mess up it again ?

You should create new array for each itemtoadd.
//For all slots
for (int i = 0; i < tempInt; i++)
{
//for all genes
Gene[] lstGene = InitializeArray<Gene>(lchromeSize);
for (int ii = 0; ii < lchromeSize; ii++)
{
//assign values to local variables
// and :
lstGene[ii].Date = ldate;
lstGene[ii].Tcode = lteacherCode;
lstGene[ii].Availabe = lavailable;
lstGene[ii].Duty = tempDuty;
lstGene[ii].Fitness = 0;
}
//End ii For
//Add the genes to slotsList
Slot itemtoadd = new Slot(lchromeSize);
itemtoadd.setChromosomes(lstGene);
slotsList.Add(itemtoadd);
}

You need to move this line:
Gene[] lstGene = InitializeArray<Gene>(lchromeSize);
to be inside the for (int i = .. loop. You are now re-using the same array for every slot - which is what you see.

Why don't you initialize your Gene[] lstGene inside a loop? Otherwise you are still referencing the same array over and over again if I am not mistaken

Related

Index was outside the bounds of the array. While Clearly it wasn't(unity)

IndexOutOfRangeException: Index was outside the bounds of the array.
RowManager.GenerateRow (System.Single hbias, System.Single vbias) (at Assets/Scripts/RowManager.cs:155)
GameManager.Update () (at Assets/Scripts/GameManager.cs:38)
The array has five cells and I index it from 0 to 4.
Unity 2021.3.8f LTS
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class Baze
{
private byte Start,End;
public Baze()
{
Start = 0;
End= 0;
}
public void SetStart(byte s)
{
Start = s;
}
public void SetEnd(byte s)
{
End = s;
}
public byte GetStart()
{
return Start;
}
public byte GetEnd()
{
return End;
}
public void Correction()
{
if(Start>End)
{
byte temp = Start;
Start = End;
End = temp;
}
}
public bool isSingular()
{
return Start == End;
}
}
class MazeLogic
{
private List<SortedSet<byte>> Groups;
private SortedSet<byte> TempSet;
private Baze TempRange;
private List<Baze> Template;
private uint[] IDs;
private bool[] Hjoints, Vjoints;
public MazeLogic()
{
Groups = new List<SortedSet<byte>>();
TempRange = new Baze();
IDs = new uint[5] {1,2,3,4,5};
Hjoints = new bool[5] {false,false,false,false,false};
Vjoints = new bool[5] {true,true,true,true,true};
TempSet = new SortedSet<byte>();
Template = new List<Baze>();
for(byte i=0;i<4;i++)
{
TempRange.SetStart(i);
TempRange.SetEnd((byte)(i + 1));
Template.Add(TempRange);
}
}
private void SetGroups(float bias)
{
uint temp = 0;
for(byte i=0;i<5;i++)
{
Hjoints[i]= false;
if (Vjoints[i])
temp = IDs[i];
else
IDs[i] = 0;
}
for (byte i = 0; i < 5; i++)
if (IDs[i] == 0)
IDs[i] = ++temp;
TempRange.SetStart(0);
for(byte i=0;i<4;i++)
{
if (Random.value > bias && IDs[Template[i].GetStart()] != IDs[Template[i].GetEnd()])
{
TempSet.Add(Template[i].GetStart());
TempSet.Add(Template[i].GetEnd());
}
else
{
TempSet.Add(Template[i].GetStart());
Groups.Add(TempSet);
TempSet.Clear();
}
}
for (byte i = 0; i < Groups.Count; i++)
for (byte j = Groups[i].Min; j < Groups[i].Max; j++)
Hjoints[j] = true;
}
private void SetVjoints(float bias)
{
bool check;
for (byte i = 0; i < Groups.Count; i++)
{
check = false;
for (byte j = Groups[i].Min; j <= Groups[i].Max; j++)
if(Random.value>bias)
{
check = true;
Vjoints[j] = true;
}
if (!check)
Vjoints[Random.Range(Groups[i].Min, Groups[i].Max + 1)] = true;
}
}
public void GenerateMaze(float hbias,float vbias)
{
SetGroups(hbias);
SetVjoints(vbias);
}
public bool[] GetHorizontalJoints()
{
return Hjoints;
}
public bool[] GetVerticalJoints()
{
return Vjoints;
}
}
public class RowManager : MonoBehaviour
{
[SerializeField] GameObject[] Hwalls;
[SerializeField] GameObject[] Vwalls;
MazeLogic ml;
void Awake()
{
ml = new MazeLogic();
}
void Start()
{
Hwalls = new GameObject[4];
Vwalls = new GameObject[5];
for (byte i = 0; i < 4; i++)
Hwalls[i] = transform.GetChild(i).gameObject;
for (byte i = 0; i < 5; i++)
Vwalls[i] = transform.GetChild((byte)(i+4)).gameObject;
}
public void GenerateRow(float hbias,float vbias)
{
ml.GenerateMaze(hbias,vbias);
for (byte i = 0; i < 4; i++)
if (ml.GetHorizontalJoints()[i])
Hwalls[i].SetActive(false);
for(byte i=0;i<5;i++)
if (ml.GetVerticalJoints()[i])
Vwalls[i].SetActive(false);//line 155
}
public void Reset()
{
for (byte i = 0; i < 4; i++)
Hwalls[i].SetActive(true);
for (byte i = 0; i < 5; i++)
Vwalls[i].SetActive(true);
}
}
and array is also not null
enter image description here
Is there any reason why Hwalls and Vwalls have to be [SerializeField] ?
If not, I would suggest removing that, since they are initialized in your Start() method and not by the user in the Editor. It could fix your problem.
As an aside, I would invite you to separate each class in their own file, making everything way more readable, and allowing you to scroll less.

How to replace duplicates in an array with 0

I have two arrays that have 20 randomly assigned elements and I need to create a method that replaces the duplicate numbers in an array with zeros but when I display the output nothing is changed.
This is the method for removing the repeating numbers. Is there a problem with the way the for loop is set up?
public static void RemoveDuplicates (int [] xArray){
for (int i = 0; i > xArray.Length-1; i++){
if (xArray[i] == xArray[i+1])
xArray[i] = 0;
}
}
and this is the whole thing
using System;
class MainClass {
public static void Main (string[] args) {
int [] student1 = new int [20];
int [] student2 = new int [20];
//int [] both = new int [40];
FillArray(student1);
FillArray(student2);
//Console.WriteLine("---------- Unsorted ----------");
//DisplayOutput(student1,student2);
Sort2Arrays(student1,student2);
//Console.WriteLine("---------- Sorted ----------");
//DisplayOutput(student1,student2);
RemoveDuplicates(student1);
RemoveDuplicates(student2);
DisplayOutput(student1, student2);
Sort2Arrays(student1,student2);
Console.WriteLine("---------- 1 and 2 no duplicates ----------");
DisplayOutput(student1, student2);
Console.WriteLine("done");
}//end main
public static void FillArray (int [] xArray){
Random rnd = new Random();
for(int i = 0; i< xArray.Length; i++){
xArray.SetValue (rnd.Next(80, 101),i);
}//end for
}//end FillArray
public static void Sort2Arrays (int [] xArray, int [] yArray){
Array.Sort(xArray);
Array.Sort(yArray);
}//end Sort2Arrays
public static void DisplayOutput (int [] xArray, int [] yArray){
for(int i = 0; i< 20; i++){
Console.WriteLine("{0}-{1}",xArray.GetValue(i),yArray.GetValue(i));
}//end for
}//end DisplayOutput
public static void RemoveDuplicates (int [] xArray){
for (int i = 0; i > xArray.Length-1; i++){
if (xArray[i] == xArray[i+1])
xArray[i] = 0;
}
}
}
Your for-loop condition is wrong, not >:
for (int i = 0; i > xArray.Length - 1; i++){
but <
for (int i = 0; i < xArray.Length - 1; i++)
with your version you will never enter the loop.
May i suggest you a different way to replace the duplicates(what you actually do), which is more efficient, more readable and more reusable:
public static void ReplaceDuplicates<T>(IList<T> xArray, T replaceWith)
{
HashSet<T> set = new HashSet<T>();
for (int i = 0; i < xArray.Count; i++)
{
if(!set.Add(xArray[i]))
{
xArray[i] = replaceWith;
}
}
}
It also doesn't need to sort the collection.
You use it in this way:
ReplaceDuplicates(student1, 0);
ReplaceDuplicates(student2, 0);
the > shouldve been <
public static void RemoveDuplicates (int [] xArray){
for (int i = 0; i < xArray.Length - 2; i++){
if (xArray[i] == xArray[i+1])
xArray[i] = 0;
}//end for
}//end RemoveDuplicates
public static void RemoveDuplicates(int[] array)
{
var foundValues = new HashSet<int>();
for (var index = 0; index < array.Length; index++)
{
var currentValue = array[index];
if (foundValues.Contains(currentValue))
{
array[index] = 0;
}
else
{
foundValues.Add(currentValue);
}
}
}

Initialize array of a class with fixed length and dynamically add values in C#

I want to have a two-dimensional game board, and every field is a custom class with information about this field, with properties. The size of the game board is known on instantiation, the values of the properties are not. After instantiation, I want to randomly set them for each field. My initial idea was to create an array, not a list, because the size of the game board is always fixed.
public class GameBoard
{
private int _xValue;
private int _yValue;
private int _bombs;
private int _fields;
public Field[][] gameBoard;
public GameBoard(int x, int y)
{
_xValue = x;
_yValue = y;
_fields = _xValue * _yValue;
gameBoard = new[] { new Field[_xValue], new Field[_yValue] };
//Here I have to initialize every Field
for (int i = 0; i < _xValue; i++)
{
for (int j = 0; j < _yValue; j++)
{
//Set properties of Field
//For example: gameBoard[i][j].IsBomb = RandomBoolean;
//Here I get NullReferenceExceptions
}
}
}
}
I do understand why this does not work. I tried lists, two-dimensional arrays or, like at the moment, a jagged array, what I would prefer. How can I solve this problem in a readable, clean way?
EDIT
The Field class:
public class Field
{
public bool IsBomb { get; set; }
public bool IsFlagged { get; set; }
}
I tried to add gameBoard[i][j] = new Field(); inside the nested forloop. This leads to an IndexOutOfRangeException.
Here is your array-property:
public Field[,] gameBoard;
And here is initialization:
public GameBoard(int x, int y)
{
_xValue = x;
_yValue = y;
_fields = _xValue * _yValue;
gameBoard = new Field[_xValue, _yValue];
for (int i = 0; i < _xValue; i++)
{
for (int j = 0; j < _yValue; j++)
{
gameBoard[i, j] = new Field();
}
}
}
Lots of confusion in here on how to work with jagged arrays. If you want to work with jagged arrays, you have to setup in such a way
//Declare jagged array, I want _xValue arrays
Field[][] gameBoard = new Field[_xValue][];
for (int i = 0; i < _xValue; i++)
{
gameBoard[i] = new Field[_yValue];
for (int j = 0; j < _yValue; j++)
{
gameBoard[i][j] = new Field(){ IsBomb = RandomBoolean};
}
}
The equivalent in a multi-dimensional array would be
//Declare multi-dimensional array of size _xValue x _yValue
Field[,] gameBoard2 = new Field[_xValue, _yValue];
for(int i = 0; i < _xValue; i++)
{
for(int j = 0; j < _yValue; j++)
{
// Instantiate the Field object at x,y
gameBoard2[i, j] = new Field { IsBomb = RandomBoolean };
}
}

Code does not recognize Listbox when I tried to fill it with array

Hi I am trying to fill a simple ListBox with array. The code that I have; it throws this error
Error 1 The name 'myArrayList' does not exist in the current context
public class Class1
{
public void FillArray()
{
int min = 1;
int max = 1000;
int[] testArray = new int[1000];
Random randNumber = new Random();
for (int i = 1; i < testArray.Length; i++)
{
testArray[i] = randNumber.Next(min, max);
}
foreach (int value in testArray)
{
myArrayList.ItemSource = testArray;
}
}
}

C# Object reference not set to an instance of an object

I am getting this NullReferenceException in the second execution of the while loop of the changeColors function.
public class myClass {
Tuple<int,int>[] theArray = new Tuple<int, int>[100];
}
public myClass() {
theArray = null;
}
public Tuple<int,int>[] findRedPixels(){
Tuple<int,int>[] myArray = new Tuple<int, int>[100];
int k = 0;
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if (graph.pixelMap [i, j].color == "red") {
myArray[k]= new Tuple<int,int>(i,j);
k++;
}
}
}
return myArray;
}
public void changeColors(){
while (true) {
theArray = findRedPixels();
foreach (var item in theArray) {
//error appears here in the second time it executes the while loop
Console.WriteLine (item.Item1 );
}
}
}
You should not return array from function findRedPixels as you have done because that array will already be initialized with 100 elements, try using List as it provide you flexibility and you can increase decrease size on fly may be something like this
public Tuple<int,int>[] findRedPixels(){
List<Tuple<int,int>> myArray = new List<Tuple<int, int>>();
int k = 0;
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if( graph.pixelMap [i, j].color=="red"){
myArray.Add( new Tuple<int,int>(i,j));
k++;
}
}
}
return myArray.ToArray();
}

Categories

Resources