ref list isn't modified outside command class - c#

I would like one class to modify the list fields of another class. I pass both list fields as references. The problem is, one list is modified in the end, and second is not. I don't understand why. I wanted to check my idea with a minimal working example, where everything works fine:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _20190424_ref_list_del
{
class Program
{
static void Main(string[] args)
{
ListManager testObj = new ListManager();
testObj.startJob();
}
}
class ListManager
{
private List<int> ListToExpand;
private List<int> ListToShorten;
public ListManager()
{
ListToExpand = new List<int>() { 1, 2, 3 };
ListToShorten = new List<int>() { 1, 2, 3 };
}
public void startJob()
{
EditList editObj = new EditList(ref ListToExpand, ref ListToShorten);
editObj.doJob();
System.Diagnostics.Debug.Print("List to expand:");
foreach (int x in ListToExpand)
{
System.Diagnostics.Debug.Print(x.ToString());
}
System.Diagnostics.Debug.Print("List to shorten:");
foreach (int x in ListToShorten)
{
System.Diagnostics.Debug.Print(x.ToString());
}
}
}
class EditList
{
private List<int> ListToExpand;
private List<int> ListToShorten;
public EditList(ref List<int> listToExpand, ref List<int> listToShorten)
{
ListToExpand = listToExpand;
ListToShorten = listToShorten;
}
public void doJob()
{
ListToExpand.Add(4);
ListToShorten.RemoveAt(0);
}
}
}
The main idea is:
Init two lists
Expand first and shorten another.
Check if there is an effect outside the working class, which modifies lists.
For this reason, I'm using ref. But the same approach in my real app fails. I have two lists too. One to be expanded, second to be shortened.
Let me explain what part of my code does: There is a list of samples from a Modbus device. Some of the samples require to be joined into bigger ones (because some of the values are so large that have values of int32 which need to be stored in two int16 registers).
I have a class with the Command design pattern which works as follows:
Create a Command object which takes:
(ref) input list of single samples
list of samples to be joined
(ref) list of samples joined to double ones
Build double samples
Remove single samples which have been joined
While testing, the list of double samples are filled, but the list of single ones isn't shortened. I don't understand why, because it looks like I'm using the same approach as in the minimal working example. Can you tell me what's wrong?
Test Case:
namespace put_samples_into_dbTests.Unit.Commands
{
[TestClass]
public class GetDoubleSamples
{
List<Sample> SingleSamples;
List<PatternSample32> SamplesPattern;
List<Sample32> ResultSamples;
int MaxSources = 2;
int MaxObjects = 3;
[TestInitialize]
public void TestInit()
{
SingleSamples = new List<Sample>();
SamplesPattern = new List<PatternSample32>();
ResultSamples = new List<Sample32>();
for (byte i = 1; i <= MaxSources; i++)
{
for (byte k = 2; k <= MaxObjects; k++)
{
SamplesPattern.Add(new PatternSample32(i, k, 1, 2));
}
}
}
[TestMethod]
public void BuildFrom1Set()
{
int howManySamples32 = MaxSources * (MaxObjects-1);
int howManySamples = MaxSources* ((1 + MaxObjects) * MaxObjects / 2) - howManySamples32 *2;
DateTime dateTime = DateTime.Now;
for (byte i = 1; i <= MaxSources; i++)
{
for (byte k = 1; k <= MaxObjects; k++)
{
for (byte l = 1; l <= k; l++)
{
SingleSamples.Add(new Sample(dateTime, i, k, l, 1, true));
}
}
}
Command command = new GetDoubleSamples(ref SingleSamples, SamplesPattern , ref ResultSamples );
command.Execute();
Assert.AreEqual(howManySamples, SingleSamples.Count); // [!]
Assert.AreEqual(howManySamples32, ResultSamples.Count);
}
Now, do take a look at my GetDoubleSamples command:
public class GetDoubleSamples : Command
{
private List<Sample> SingleSamples;
private List<PatternSample32> DoubleSamplesPattern;
private List<Sample32> ResultSamples;
private List<Sample> ProcessedSamples;
public GetDoubleSamples (ref List<Sample> singleSamples, List<PatternSamples32> doubleSamplesPattern, ref List<Sample32> resultSamples)
{
SingleSamples = singleSamples;
doubleSamplesPattern = doubleSamplesPattern;
ResultSamples = resultSamples;
ProcessedSamples = new List<Sample>();
}
public void Execute()
{
SortSamples();
foreach (List<Sample> samplesSet in GenerateSets())
{
ResultSamples.AddRange(BuildDoubles(samplesSet ));
}
DeleteProcessedSamples();
}
private void DeleteProcessedSamples()
{
SingleSamples = SingleSamples.Except(ProcessedSamples).ToList();
}
}
And the problem is, when I check for the amount of created double samples - it's okay. But the same (I suppose) kind of list of simple samples isn't reduced of processed samples. When I debug the code, I see that inside the class the mentioned list is modified. But once I get outside Execute methods and get outside Command class, I lose that modified list and get back to the original one. Just as if my list wasn't passed as a reference.
Do you have any idea what might be wrong?
Any suggestions, also about rearranging my test method, will be appreciated! :-)

Related

Execute methods following the order of a list in C#

I have a unity project and want to call methods one after another using a predefined list.
In this test scenario I want to execute startTrialWithFixedValue1() two times, startTrialWithFixedValue2() two times and startTrialWithRandomValue() one time in the end. Every time the user makes an input, I want to execute the next method from the list. There are two major problems with my code:
(1) Whenever I use an if statement with return the variable countTrial becomes unreachable. The debug log shows always 0:1 and the first method is executed all the time.
(2) If I exclude the return statement, all methods are started at once.
[EDIT] To specify my question: How can I execute methods following the order of a given list.
Script A:
public int countTrial;
public int maxTrials = 16;
public Spawner spawner;
List<int> trialMarkers = new List<int>() {1, 1, 2, 2, 3};
public void chooseNextTrial()
{
for (int countTrial = 0; countTrial < maxTrials; countTrial++)
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
return;
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
return;
}
else
{
spawner.startTrialWithRandomValue();
return;
}
}
Script B:
public void handleUserInput()
{
if (Input.GetButtonDown("Fire3"))
{
deleteAllChildren();
chooseTrial.chooseNextTrial();
}
}
}
Hope you guys can help me!
[EDIT2] As suggested by Programmer: Remove the return statement in that function then run it again. Copy and paste the result of Debug.Log(countTrial + ": " + trialMarkers[countTrial]); the result is always:
5:3
5:3
5:3
...
You need to remove the For loop and handle the execution of Method more manualy
public int countTrial = 0;
public int maxTrials = 16;
public Spawner spawner;
List<int> trialMarkers = new List<int>() {1, 1, 2, 2, 3};
public void chooseNextTrial()
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
}
else
{
spawner.startTrialWithRandomValue();
}
}
And then inside your second script (Script B) which handles the user input
public void handleUserInput()
{
if (Input.GetButtonDown("Fire3"))
{
deleteAllChildren();
chooseTrial.chooseNextTrial();
chooseTrial.countTrial++;
}
}
End line: You shouldnt use a Fop loop since you want the sequence to be startied whith a player input action and handle it like this. Also adding a method like this:
public void NextCounter()
{
if(countTrial<trialMarkers.Count)
countTrial++
}
In your Script A and then call it like this in Script B to avoid your counter going above the list count.
chooseTrial.NextCounter();
Insteed of using the countTrial++ in SCript B
When you return in the method you are breaking out of your loop.
for (int countTrial = 0; countTrial < (maxTrials <= trialMarkers.Count ? maxTrails : trialMarkers.Count) ; countTrial++)
{
Debug.Log(countTrial + ": " + trialMarkers[countTrial]);
if (trialMarkers[countTrial] == 1)
{
spawner.startTrialWithFixedValue1();
}
if (trialMarkers[countTrial] == 2)
{
spawner.startTrialWithFixedValue2();
}
else
{
spawner.startTrialWithRandomValue();
}
}
Will execute the way you are asking. Also note I changed your iterator so that you do not get an object reference error in your loop.
How about doing something similar to what you describe in the title (which gives the impression that you have a "list of functions"). This example is easily extensible:
private Action[] _functions;
public void MainEntryPoint()
{
_functions = new Action[] { StartTrialWithFixedValue1, StartTrialWithFixedValue2, StartTrialWithRandomValue };
List<int> trialMarkers = new List<int>() { 1, 1, 2, 2, 3 };
DoThings(trialMarkers);
}
public void DoThings(IEnumerable<int> indexesOfFuctions)
{
foreach (var index in indexesOfFuctions)
{
_functions[index-1]();
}
}
private void StartTrialWithFixedValue1()
{
Trace.WriteLine("StartTrialWithFixedValue1");
}
private void StartTrialWithFixedValue2()
{
Trace.WriteLine("StartTrialWithFixedValue2");
}
private void StartTrialWithRandomValue()
{
Trace.WriteLine("StartTrialWithRandomValue");
}
I create an "array of functions" (actually of Delegates to functions), and then I use your list of instructions to execute them.

Solving Towers of Hanoi in C# using recursion

I'm facing the Towers of Hanoi problem, I read the concept and the recursive way of solving it from wikipedia, but I can not see what I'm missing in the implementation of the steps mentioned in wikipedia.
I have seen many examples here but I don't want my program to print the steps, I want the program solves the problem moving the "discs" between 3 collections, in my code I'm using 3 Stacks to simulate the pegs.
Here is my current code:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var hs = new HanoiSolver(discs: 3);
hs.Solve();
Console.ReadKey();
}
}
class HanoiSolver
{
private int TotalDiscs { get; set; } = 0;
private Stack<int> FirstPeg { get; set; } = new Stack<int>();
private Stack<int> SecondPeg { get; set; } = new Stack<int>();
private Stack<int> ThirdPeg { get; set; } = new Stack<int>();
public HanoiSolver(int discs = 3)
{
TotalDiscs = discs;
//Create list of items (discs)
var discList = Enumerable.Range(1, TotalDiscs).Reverse();
//Add items (discs) to first peg
foreach (var d in discList)
{
FirstPeg.Push(d);
}
}
public void Solve()
{
if (ThirdPeg.Count != TotalDiscs)
{
PrintPegs();
//Move first item from firstpeg to secondpeg
if (FirstPeg.Any())
{
var fp_f = FirstPeg.Pop();
SecondPeg.Push(fp_f);
}
PrintPegs();
//Move second item from firstpeg to thirdpeg
if (FirstPeg.Any())
{
var fp_s = FirstPeg.Pop();
ThirdPeg.Push(fp_s);
}
PrintPegs();
//Move first item from secondpeg to thirdpeg
if (SecondPeg.Any())
{
var sp_f = SecondPeg.Pop();
ThirdPeg.Push(sp_f);
}
PrintPegs();
Solve();
}
}
private void PrintPegs()
{
var fp = FirstPeg.Select(x => x.ToString()).ToList();
if (fp.Count < TotalDiscs)
{
fp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - fp.Count)));
}
var sp = SecondPeg.Select(x => x.ToString()).ToList();
if (sp.Count < TotalDiscs)
{
sp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - sp.Count)));
}
var tp = ThirdPeg.Select(x => x.ToString()).ToList();
if (tp.Count < TotalDiscs)
{
tp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - tp.Count)));
}
Console.WriteLine($"{"[First Peg]",10}" + $"{"[Second Peg]",10}" + $"{"[Third Peg]",10}");
for (var i = 0; i < TotalDiscs; i++)
{
Console.WriteLine($"{fp[i],10}" +
$"{sp[i],10}" +
$"{tp[i],10}");
}
}
}
In order to make a recursive method you need one or more base cases where the recursion will end and then one or more recursive calls that break the problem down closer to one of the base cases. For Towers of Hanoi the idea is that moving n discs from Peg A to Peg C is just moving n-1 from Peg A to Peg B, then moving the nth from A to C and finally moving the n-1 discs from C to B. That will eventually get you down to moving no discs which is your base case. That can be done in a recursive method very simply like this.
private static void Move(
int discs,
Stack<int> fromPeg,
Stack<int> toPeg,
Stack<int> otherPeg)
{
if (discs == 0)
{
return;
}
Move(discs - 1, fromPeg, otherPeg, toPeg);
toPeg.Push(fromPeg.Pop());
Move(discs -1, otherPeg, toPeg, fromPeg);
}
When you are implementing TOH, this means you are new to DS and data types. So one must use the data type which is not present in DS like stack and queue. So the below approach is using array.
using System;
using static System.Console;
namespace TOH
{
class Program
{
// Problem statement
//Create an array tower(a) containing all element in ascending order
public static int[] towerSource = new int[] { 1, 3, 5,6,7,9,11,12,13,14,15,16,17};
//solution statement
//we have two more towers with same capacity, tower(b) as auxiliary and tower(c) as destination
public static int[] towerAuxiliary;
public static int[] towerDestination;
public static void CreateTowers()
{
towerAuxiliary = new int[towerSource.Length];
towerDestination = new int[towerSource.Length];
}
public static void Print(int[] tower)
{
for (int i = 0; i < tower.Length; i++)
Write(tower[i].ToString());
WriteLine("--------next run-------------");
}
//start operation
public static void TOH(int numberOfDisks, int[] source,int[] auxiliary,int[] destination)
{
//check if there is only one disk in source
if(numberOfDisks == 1)
{
//move to destination and come out
towerDestination[numberOfDisks-1] = towerSource[numberOfDisks-1];
Print(towerDestination);
return;
}
//move n-1 disks from source to auxiliary
TOH(numberOfDisks - 1, towerSource, towerAuxiliary, towerDestination);
towerDestination[numberOfDisks-1] = towerSource[numberOfDisks-1];
//move nth disc from source to dest
//this is being handeled by if condition
//move n-1 disks from auxiliary to dest
TOH(numberOfDisks - 1, towerAuxiliary, towerSource, towerDestination);
return;
}
static void Main(string[] args)
{
CreateTowers();
TOH(towerSource.Length, towerSource, towerAuxiliary, towerDestination);
}
}
}

Recursive function overwriting output list

I was working on a class to find every combination of N lists. The combination algorithm seems to work flawlessly (when I step through it) but I am having trouble saving off my results. I want to store all the resulting arrays in another list to use later, but when I do the last array combination overwrites all the previous ones. Example input/outputs and my code are below. Does anyone have any ideas how I can fix this? (I've tried reference parameters and global lists with the same result).
/*
Input: A B C
X Y
Expected Output: A X
A Y
B X
B Y
C X
C Y
Actual Output: C Y
C Y
C Y
C Y
C Y
C Y
*/
public class Combination<T>{
private static void Combine(T[] res, int ix, List<List<T>> data, ref List<T[]> allCombos){
foreach (T v in data[ix]){
res[ix] = v;
if (ix >= data.Count - 1){
allCombos.Add(res);
}else{
Combine(res, ix + 1, data, ref allCombos);
}
}
}
public static List<T[]> Combine(List<List<T>> data){
List<T[]> allCombos = new List<T[]>();
Combine(new T[data.Count], 0, data, ref allCombos);
return allCombos;
}
}
The main problem here is that you only ever allocate a single T[] instance. Which you just add to your List<T[]> over and over.
Instead of this:
allCombos.Add(res);
You should try this:
allCombos.Add(res.ToArray());
That will create a new copy of the array each time as you add it to the list.
try this. I think this should work. I am not on terminal to test it.
public class Combination<T>
{
static T[] res;
private static void Combine(int ix, List<List<T>> data, ref List<T[]> allCombos)
{
foreach (T v in data[ix])
{
res[ix] = v;
if (ix >= data.Count - 1)
{
allCombos.Add(res);
}
else
{
Combine(res, ix + 1, data, ref allCombos);
}
}
}
public static List<T[]> Combine(List<List<T>> data)
{
List<T[]> allCombos = new List<T[]>();
res = new T[data.Count];
Combine(0, data, ref allCombos);
return allCombos;
}
}
The problem is that res argument is reused and overwritten in each iteration. Here is my solution for you.
using System;
using System.Linq;
using System.Collections.Generic;
....
private IEnumerable<T[]> Combine<T>(IEnumerable<T[]> data)
{
if (!data.Any())
yield break;
var head = data.First();
var tail = Combine(data.Skip(1));
foreach (var e in head)
{
var list = new T[] {e};
if (!tail.Any())
yield return list;
else
{
foreach (var t in tail)
{
yield return list.Concat(t).ToArray();
}
}
}
}
For the record, I had a similar issue, with a list of custom objects recently. What did it for me was basically creating a new object, using the object that used to get overwriten ("subTree") as the basis.
//Do this
TreeView newTree= new TreeView {
name = subTree.name,
children = subTree.children
};
actualTree.Add(newTree);
//Not this
actualTree.Add(subTree)
If I did not do that, I would have gotten the last "subTree" object everytime I tried to add a TreeView element to the "actualTree" List. The solution is to create a new object with the values that you need from other object whenever you have to add an element to your list, so that you are not always adding the same object.

C# Invoke with out parameter using .net 3.5

I want to invoke a function with two out parameters and bool as return value. Now my problem is I see that those two parameters are changed when I debug, but still they are back to length = 0 (the way they are initialized) when the function returns.
I've seen that there's a great solution for the .net-framework 4, but unfortunaly I have to use the .net-framework 3.5.
Here's my code:
public delegate bool GetAllCheckedItemsDelegate(out int[] cTypes, out int[] cFiles);
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles )
{
if (ListView.InvokeRequired)
{
cTypes = new int[0];
cFiles = new int[0];
return (bool)ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems), new object[] { cTypes, cFiles });
}
else
{
cTypes = new int[ListView.CheckedItems.Count];
cFiles = new int[ListView.CheckedItems.Count];
for (int i = 0; i < ListView.CheckedItems.Count; i++)
{
// ......code......
}
return (ListView.CheckedItems.Count > 0);
}
}
I do not really like "out" keyword, so what about of using a class (Row) that contains information:
using SCG = System.Collections.Generic;
using System.Linq;
public class Row {
public int CheckedType { get; set; }
public int CheckedFile { get; set; }
}
...
public delegate SCG.IEnumerable<Row> GetAllCheckedItemsDelegate();
public bool GetAllCheckedItems() {
if (ListView.InvokeRequired) {
var rows = ListView.Invoke(new GetAllCheckedItemsDelegate(GetAllCheckedItems)
, new object[] {});
return rows.Count() > 0;
} else {
var rows = new SCG.List<Row>();
for (int i = 0; i < ListView.CheckedItems.Count; i++) {
// create and set row
var row = new Row { CheckedType = x, CheckedFile = y };
...
rows.Add(row);
}
return rows.AsReadOnly();
}
}
return (bool)ListView.Invoke(..., new object[] { cTypes, cFiles });
That modifies the object[] elements. C# does not provide syntax to get it to update the arguments of the method, there's an extra level of indirection that you can't bridge with code. It is up to you to copy the references back. Nothing to worry about, you are not actually copying the array content, just the references:
var args = new object[] { null, null };
var dlg = new GetAllCheckedItemsDelegate(GetAllCheckedItems);
var retval = (bool)ListView.Invoke(dlg, args);
cTypes = (int[])args[0];
cFiles = (int[])args[1];
return retval;
Nothing pretty about it of course. Do keep in mind that you are certainly doing something very unpretty, you have no guarantee whatsoever that you get the items you expect to get. This code runs at a very unpredictable moment in time, quite disjoint from the code that's running on the UI thread. If the user is busy checking items while the worker is running then you get a quite random selection. A snapshot of the list box state that very quickly turns stale.
This almost always requires you to disable the list box while the worker is running so you provide a guarantee that the result you compute matches the list. That in turn means that it is no longer useful to write this code at all, you might as well obtain the list before you start the thread. Which is the real solution.
I've found a solution that works for me. Still I'm open to different (and better) approaches if you think that this is not a good way to solve this.
public delegate bool BoolDelegate();
public bool GetAllCheckedItems(out int[] cTypes , out int[] cFiles )
{
if (ListView.InvokeRequired)
{
int[] cTypesHelpVar = new int[0];
int[] cFilesHelpVar = new int[0];
bool ret = (bool)ListView.Invoke((BoolDelegate) (() => GetAllCheckedItems(out cTypesHelpVar, out cFilesHelpVar)));
cTypes = cTypesHelpVar;
cFiles = cFilesHelpVar;
return ret;
}
else
{
cTypes = new int[ListView.CheckedItems.Count];
cFiles = new int[ListView.CheckedItems.Count];
for (int i = 0; i < ListView.CheckedItems.Count; i++)
{
//.... code ....
}
return (ListView.CheckedItems.Count > 0);
}
}

Java and C# pass by value differences

I think the code below will make my question clear. If they both pass by value, why are they different.
C# below:
static void Main(string[] args)
{
var list = new List<int> {1, 2, 3,};
ChangeVars(list);
foreach (var i in list)
{
Console.WriteLine(i);
}
Console.Read();
}
private static void ChangeVars(List<int> list)
{
for(int i = 0; i < list.Count; i++)
{
list[i] = 23;
}
}
Returns 23, 23, 23,
Java below:
public static void main(String[] args)
{
List<Integer> goods = new ArrayList<Integer>();
goods.add(1); goods.add(2); goods.add(3);
ChangeThings(goods);
for(int item: goods)
{
System.out.println(item);
}
}
private static void ChangeThings(List<Integer> goods)
{
for(int item: goods)
{
item = 23;
}
}
Returns 1, 2, 3.
I don't understand the discrepancy.
You're seeing the difference between a foreach loop and a regular for loop.
Your Java code only assigns the local item variable; it doesn't actually modify the list.
If you write goods.set(i, 23), you will modify the list.
The "discrepancy" has nothing to do with passing by value. You are using a different kind of loop in Java, the one where the list is not modified. That's why you see the difference.
If you replace the Java loop with a for (int i = 0 ... ) kind or replace the C# loop with a foreach, there would be no differences between the two programs. In fact, C# program will not compile, because assigning the loop variable is a very common error:
foreach(int item in list)
{
item = 23; // <<=== This will not compile in C#
}
The list is passed by reference in both cases. Just, but
for(int item: goods)
{
item = 23;
}
doesn't extract a reference to the items from the list but copy it to a variable, you would get the same in C# if you wrote x=list[i] followed be x=23.
you must use
for(int i=0;i<goods.size() )
{
goods.set(i, 23);
}

Categories