How to use a variable inside a variable name c# [duplicate] - c#

This question already has answers here:
Create dynamic variable name
(5 answers)
Closed 3 years ago.
I have 3 variables called gxpos, gypos and gzpos. I have a method called moove(), with a string argument axis (x, y or z) which I want to be able to change the value of both 3 variables (gxpos, gypos, gzpos).
In the code sample, I have represented the locations where I want to have the axis variable by this ?.
public void moove(string axis)
{
g(?)pos = (?)pos + trkSizeStep.Value;
if (g(?)pos != m(?)pos || -g(?)pos != m(?)pos)
{
(?)pos = g(?)pos;
port.WriteLine(axis + (?)pos);
lblpos(?).Text = (?)pos.ToString();
}
else
{
errorLimit(axis, 1);
}
}

Using Dictionaries:
var gpos = new Dictionary<string, int> { { "x", 0 }, { "y", 0 }, { "z", 0 } };
var mpos = new Dictionary<string, int> { { "x", 0 }, { "y", 0 }, { "z", 0 } };
var pos = new Dictionary<string, int> { { "x", 0 }, { "y", 0 }, { "z", 0 } };
var lblpos = new Dictionary<string, Label> { { "x", lblxpos }, { "y", lblypos }, { "z", lblzpos } };
public void moove(string axis)
{
gpos[axis] = pos[axis] + trkSizeStep.Value;
if (gpos[axis] != mpos[axis] || -gpos[axis] != mpos[axis])
{
pos[axis] = gpos[axis];
port.WriteLine(axis + pos[axis]);
lblpos[axis].Text = pos[axis].ToString();
}
else
{
errorLimit(axis, 1);
}
}

This is not possible in C# without reflection or the use of external tools such as T4 Templates.
However, you may be able to get around this by using arrays:
int[] gpos = new int[] { gxpos, gypos, gzpos };
int[] pos = new int[] { xpos, ypos, zpos };
int[] mpos = new int[] { mxpos, mypos, mzpos };
string axisNames = new string[] { "x", "y", "z" };
public void moove(int axis)
{
gpos[axis] = pos[axis] + trkSizeStep.Value;
if (gpos[axis] != mpos[axis] || -gpos[axis] != mpos[axis])
{
pos[axis] = gpos[axis];
port.WriteLine(axisNames[axis] + pos[axis]);
lblpos[axis].Text = pos[axis].ToString();
}
else
{
errorLimit(axisNames[axis], 1);
}
}
Or better yet, take advantage of Vector<T> and friends

Related

xUnit testing method that utilises UI

I am new to C#. I have been trying to write a xUnit Test for the method below ("ExecuteExportCsvCommand()"). However, it has some UI control as you can see below.
Therefore, I don't know how to test the function. If anyone can explain, I would be really thankful.
public void ExecuteExportCsvCommand()
{
ExecuteCancelPopOutWindowCommand();
var previousState = View.IsEnabled;
View.IsEnabled = false;
try
{
var exportDialog = new ExportPrintDataDialog();
var result = exportDialog.ShowDialog();
if (result.GetValueOrDefault())
{
var projectData = _projectService.GetProject3dObject(Project.Id);
IEnumerable<object> orderedList;
orderedList = projectData.Select((x, i) => new ExportData {
Index = i,
Time = x.Time,
LayerNumber = x.LayerNumber,
X = x.X,
Y = x.Y,
Z = x.Z,
ArcVoltage = x.ArcVoltage,
Current = x.Current,
WireFeedSpeed = x.WireFeedSpeed,
WireFeedSpeedB = x.WireFeedSpeedB,
RatioWireFeedSpeed = (x.WireFeedSpeed == 0) ? 0 : x.WireFeedSpeedB / x.WireFeedSpeed,
BuildHeight = x.WallHeight,
LeadTemperature = x.LeadTemperature,
TrailTemperature = x.TrailTemperature,
OxygenLevel = x.OxygenLevel,
GasFlowA = x.GasFlow.First(),
GasFlowB = x.GasFlow.Last(),
TempChannels = x.TempChannels //preferably last as array of 8 values
}).ToList();
//Define Column headers
var heightHeader = _options.CorriOptions.Value.UseWallHeight ? "Wall Height" : "Layer Height";
var wfsHeader = Project.ProcessEnum == EnumProjectProcess.CW_MIG
? new []{ "Hot Wire Feed Speed", "Cold Wire Feed Speed" }
: new[] { "Wire Feed Speed 1", "Wire Feed Speed 2" };
var headers = new Dictionary<string, string>()
{
{ "Index" , "Ordinal Number" },
{ "Time" , "Time" },
{ "LayerNumber" , "Layer Number" },
{ "X" , "Pos X" },
{ "Y" , "Pos Y" },
{ "Z" , "Pos Z" },
{ "ArcVoltage" , "Arc Voltage" },
{ "Current" , "Current" },
{ "WireFeedSpeed" , wfsHeader.First() },
{ "WireFeedSpeedB" , wfsHeader.Last() },
{"RatioWireFeedSpeed", "R-Ratio"},
{ "BuildHeight" , heightHeader },
{ "LeadTemperature" , "Lead Temperature" },
{ "TrailTemperature" , "Trail Temperature" },
{ "OxygenLevel" , "Oxygen Level" },
{ "GasFlowA" , "GasFlow Channel A" },
{ "GasFlowB" , "GasFlow Channel B" },
{ "TempChannels" , "End Effector Temperature (Channels 1 - 8)" }
};
var saveFileDialog = new SaveFileDialog
{
Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*",
FilterIndex = 1,
RestoreDirectory = true,
FileName = string.Concat(DateTime.Now.ToString("yyyy-MM-ddTHHmm"), "_log"),
};
if (saveFileDialog.ShowDialog().GetValueOrDefault())
{
using var writer = new StreamWriter(saveFileDialog.FileName);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap(new ExportDataMapper(headers));
csv.WriteRecords(orderedList);
}
}
}
finally
{
View.IsEnabled = previousState;
ExportDataBtnChecked = false;
}
}
The test environment was set up already as you can see below. I just have to write the test for the method mentioned. If you need further details, please let me know. thanks.
public class ProjectPrintViewModelTests
{
private readonly ProjectPrintViewModel _sut;
private readonly IHost _host;
private readonly Mock<IPermissionChecker> _permissionChecker = new Mock<IPermissionChecker>();
private readonly Mock<ILogService> _logService = new Mock<ILogService>();
private readonly Mock<IAuditService> _auditService = new Mock<IAuditService>();
private readonly Mock<IProjectService> _projectService = new Mock<IProjectService>();
public ProjectPrintViewModelTests()
{
var colorList = new List<string> {
"DefaultMinColor",
"DefaultLowColor",
"DefaultNormColor",
"DefaultHighColor",
"DefaultMaxColor"
};
var app = new Application();
colorList.ForEach(x => app.Resources.Add(x, Color.FromRgb(255, 255, 255)));
_host = MockEnvironment.BuildHost();
IoCContainer.SetServiceProvider(_host.Services);
var options = _host.Services.GetRequiredService<OptionsContainer>();
var valueService = _host.Services.GetRequiredService<IValuePointService>();
var project = new ProjectViewModel(options);
_sut = new ProjectPrintViewModel(
options,
project,
_logService.Object,
_permissionChecker.Object,
_auditService.Object,
_projectService.Object,
valueService,
false);
}
/// Write Tests Below Here
[Fact]
public void ExecuteCsvFileCommand_WhenValueAreValid()
{
//Assemble
//Act
_sut.ExecuteExportCsvCommand();
//Assert
This is one of the many disadvantages of having poor design and non-clean architecture.. Separating UI code from business logic helps you in testing your business logic well.
Keep in mind that unit tests should run/return as fast as possible. Apparently, showing a SaveFileDialog will stop the test until a user selects the path, this is wrong!
You should pull all UI-related code out to a separate component that delivers UI services, For example:
public interface IUiServices
{
void CancelPopOutWindow();
void SaveViewState();
void RestoreViewState();
bool ShowExportDialog();
string ShowSaveFileDialog();
}
The most important part is, when testing, you'd mock the UIServices to not do any real UI work (Ex. opinging SaveFileDialog, it will just return a valid test path to save files in there).. So ExecuteExportCsvCommand can be look like this..
public void ExecuteExportCsvCommand()
{
_uiServices.CancelPopOutWindow();
_uiServices.SaveViewState();
try
{
var b = _uiServices.ShowExportDialog();
if (b)
{
var projectData = _projectService.GetProject3dObject(Project.Id);
IEnumerable<object> orderedList;
orderedList = projectData.Select((x, i) => new ExportData {
Index = i,
Time = x.Time,
LayerNumber = x.LayerNumber,
X = x.X,
Y = x.Y,
Z = x.Z,
ArcVoltage = x.ArcVoltage,
Current = x.Current,
WireFeedSpeed = x.WireFeedSpeed,
WireFeedSpeedB = x.WireFeedSpeedB,
RatioWireFeedSpeed = (x.WireFeedSpeed == 0) ? 0 : x.WireFeedSpeedB / x.WireFeedSpeed,
BuildHeight = x.WallHeight,
LeadTemperature = x.LeadTemperature,
TrailTemperature = x.TrailTemperature,
OxygenLevel = x.OxygenLevel,
GasFlowA = x.GasFlow.First(),
GasFlowB = x.GasFlow.Last(),
TempChannels = x.TempChannels //preferably last as array of 8 values
}).ToList();
//Define Column headers
var heightHeader = _options.CorriOptions.Value.UseWallHeight ? "Wall Height" : "Layer Height";
var wfsHeader = Project.ProcessEnum == EnumProjectProcess.CW_MIG
? new []{ "Hot Wire Feed Speed", "Cold Wire Feed Speed" }
: new[] { "Wire Feed Speed 1", "Wire Feed Speed 2" };
var headers = new Dictionary<string, string>()
{
{ "Index" , "Ordinal Number" },
{ "Time" , "Time" },
{ "LayerNumber" , "Layer Number" },
{ "X" , "Pos X" },
{ "Y" , "Pos Y" },
{ "Z" , "Pos Z" },
{ "ArcVoltage" , "Arc Voltage" },
{ "Current" , "Current" },
{ "WireFeedSpeed" , wfsHeader.First() },
{ "WireFeedSpeedB" , wfsHeader.Last() },
{"RatioWireFeedSpeed", "R-Ratio"},
{ "BuildHeight" , heightHeader },
{ "LeadTemperature" , "Lead Temperature" },
{ "TrailTemperature" , "Trail Temperature" },
{ "OxygenLevel" , "Oxygen Level" },
{ "GasFlowA" , "GasFlow Channel A" },
{ "GasFlowB" , "GasFlow Channel B" },
{ "TempChannels" , "End Effector Temperature (Channels 1 - 8)" }
};
string path = _uiServices.ShowSaveFileDialog();
if (!string.IsNullOrEmpty(path))
{
using var writer = new StreamWriter(path);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap(new ExportDataMapper(headers));
csv.WriteRecords(orderedList);
}
}
}
finally
{
_uiServices.RestoreViewState();
ExportDataBtnChecked = false;
}
}

C# the best way to compare 4 strings and ignore the empty one

I want to compare 4 strings if they are equal or not. The problem is that I have to ignore the empty strings, but if they are all empty then the method must also return true, because all empty strings are equal. I could write everything down like
if(string1 != string.Empty && string2 != string.Empty &&
string1 != string2)
{
return false
}
if(string1 != string.Empty && string2 != string.Empty && string3 != etc....
But I think there is a better way then writing out all the possibilities.
But how?
This will check that all non-empty or non-null strings are equal:
public static bool CheckNonEmptyStringsForEquality(params string[] strings)
{
string target = strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));
if (target == null)
return false;
return strings.All(s => string.IsNullOrEmpty(s) || s == target);
}
Use it like this:
Console.WriteLine(
CheckNonEmptyStringsForEquality("", "X", "X")); // Prints true
Console.WriteLine(
CheckNonEmptyStringsForEquality("", "X", "Y")); // Prints false
Console.WriteLine(
CheckNonEmptyStringsForEquality("", "X", "", "X", "", "X", "")); // Prints true
Note: If you want to return true if all strings are null or empty, do this instead:
public static bool CheckNonEmptyStringsForEquality(params string[] strings)
{
string target = strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));
return strings.All(s => string.IsNullOrEmpty(s) || s == target);
}
Then this will return true too:
Console.WriteLine(
CheckNonEmptyStringsForEquality("", "", "")); // Prints true
Something like this? Do Distinct and check the Count on an Array of strings.
var strings = new string[] {"str1", "str2", "str3"};
if( (strings.Where(s=>!string.IsNullOrEmpty(s)).Distinct().Count() == 1))
{
// unique
}
Try this:
static void Main(string[] args)
{
var text1 = new[] { "x", "y", "z", "w" };
var text2 = new[] { "x", "y", null, "" };
var text3 = new[] { "x", "x", "x", "x" };
var text4 = new[] { "x", "x", null, "" };
MyComparer(text1); // False
MyComparer(text2); // False
MyComparer(text3); // True
MyComparer(text4); // True
}
private static bool MyComparer(IEnumerable<string> array)
{
return array.Where(t => !string.IsNullOrEmpty(t)).Distinct().Count() == 1;
}
//Hope this helps
string a = "";
string b = "mystring";
string c = "mystring";
string d = "mystring";
bool isEqual = true;
ArrayList array = new ArrayList();
array.Add(a);
array.Add(b);
array.Add(c);
array.Add(d);
foreach (string stringMemeber in array)
{
if (string.IsNullOrEmpty(stringMemeber))
{
continue;
}
else
{
foreach (string NestedStringMember in array)
{
if (string.IsNullOrEmpty(NestedStringMember))
{
continue;
}
else
{
if (string.Compare(stringMemeber,NestedStringMember)!=0)
{
isEqual = false;
break;
}
}
}
if (!isEqual)
{
break;
}
}
}
Console.WriteLine("The strings are equal: " + isEqual.ToString());
if you pass the string in an array,
var collection = new string[] { "India", "", "India", "India" };
var isEqual = collection.Distinct().Contains("") ? collection.Distinct().Count() <= 2 : collection.Distinct().Count() == 1;

Making a predictive text algorithm go faster

I am working on a windows phone dialler app and I have implemented prediction text in my app. When user taps on keypad, contacts that match input are generated. Prediction is too slow, it also blocks my main thread that's why I have implemented BackGroundWorker But still having problems with the performance
My code is:
private void dialer_TextChanged(object sender, TextChangedEventArgs e)
{
MainPage.DialerText = dialer.Text;
if(!bw1.IsBusy)
bw1.RunWorkerAsync();
}
void bw1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
var digitMap = new Dictionary<int, string>() {
{ 1, "" },
{ 2, "[abcABC]" },
{ 3, "[defDEF]" },
{ 4, "[ghiGHI]" },
{ 5, "[jklJKL]" },
{ 6, "[mnoMNO]" },
{ 7, "[pqrsPQRS]" },
{ 8, "[tuvTUV]" },
{ 9, "[wxyzWXYZ]" },
{ 0, "" },
};
var enteredDigits = DialerText;
var charsAsInts = enteredDigits.ToCharArray().Select(x => int.Parse(x.ToString()));
var regexBuilder = new StringBuilder();
foreach (var val in charsAsInts)
regexBuilder.Append(digitMap[val]);
MainPage.pattern = regexBuilder.ToString();
MainPage.pattern = ".*" + MainPage.pattern + ".*";
}
catch (Exception f)
{
// MessageBox.Show(f.Message);
}
}
void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SearchListbox.ItemsSource = listobj.FindAll(x => x.PhoneNumbers.Any(a=>a.Contains(MainPage.DialerText)) | Regex.IsMatch(x.FirstName, MainPage.pattern));
}
BackGroundWorker also blocking my main thread, hence when I tap on the keypad there's a lag while input values are added to the TextBox. I want to add input to the TextTox without any lag, how to do it? Thank you.
You can grab a real speed-up here by moving away from exhaustive searches of the entire wordlist and instead, putting your words into a more efficient data-structure.
For lightning fast lookups over any size of word list (but more expensive in terms of memory), you should build a tree structure that contains your entire word list.
The root node represents zero dialled digits, and it is connected to (up to) ten more nodes, where the edges connecting the nodes represent one of the possible numbers pressed for 0 to 9.
Each node then contains the possible words that can be formed from the path taken through the tree from the root node, where the path is representative of the numbers pressed.
This means that a search no longer requires iterating the entire word list and can be completed in very few operations.
Here's the concept in practice with a 370000 word-list I found on the web. Search takes around about 0.02ms on my desktop. Nice and fast. Seems to take about ~50MB in memory.
void Main()
{
var rootNode = new Node();
//probably a bad idea, better to await in an async method
LoadNode(rootNode).Wait();
//let's search a few times to get meaningful timings
for(var i = 0; i < 5; ++i)
{
//"acres" in text-ese (specifically chosen for ambiguity)
var searchTerm = "22737";
var sw = Stopwatch.StartNew();
var wordList = rootNode.Search(searchTerm);
Console.WriteLine("Search complete in {0} ms",
sw.Elapsed.TotalMilliseconds);
Console.WriteLine("Search for {0}:", searchTerm);
foreach(var word in wordList)
{
Console.WriteLine("Found {0}", word);
}
}
GC.Collect();
var bytesAllocated = GC.GetTotalMemory(true);
Console.WriteLine("Allocated {0} bytes", bytesAllocated);
}
async Task LoadNode(Node rootNode)
{
var wordListUrl =
"https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt";
Console.WriteLine("Loading words from {0}", wordListUrl);
using(var httpClient = new HttpClient())
using(var stream = await httpClient.GetStreamAsync(wordListUrl))
using(var reader = new StreamReader(stream))
{
var wordCount = 0;
string word;
while( (word = await reader.ReadLineAsync()) != null )
{
word = word.ToLowerInvariant();
if(!Regex.IsMatch(word,#"^[a-z]+$"))
{
continue;
}
rootNode.Add(word);
wordCount++;
}
Console.WriteLine("Loaded {0} words", wordCount);
}
}
class Node
{
static Dictionary<int, string> digitMap = new Dictionary<int, string>() {
{ 1, "" },
{ 2, "abcABC" },
{ 3, "defDEF" },
{ 4, "ghiGHI" },
{ 5, "jklJKL" },
{ 6, "mnoMNO" },
{ 7, "pqrsPQRS" },
{ 8, "tuvTUV" },
{ 9, "wxyzWXYZ" },
{ 0, "" }};
static Dictionary<char,int> letterMap;
static Node()
{
letterMap = digitMap
.SelectMany(m => m.Value.Select(c=>new {ch = c, num = m.Key}))
.ToDictionary(x => x.ch, x => x.num);
}
List<string> words = new List<string>();
//the edges collection has exactly 10
//slots which represent the numbers [0-9]
Node[] edges = new Node[10];
public IEnumerable<string> Words{get{
return words;
}}
public void Add(string word, int pos = 0)
{
if(pos == word.Length)
{
if(word.Length > 0)
{
words.Add(word);
}
return;
}
var currentChar = word[pos];
int edgeIndex = letterMap[currentChar];
if(edges[edgeIndex] == null)
{
edges[edgeIndex] = new Node();
}
var nextNode = edges[edgeIndex];
nextNode.Add(word, pos+1);
}
public Node FindMostPopulatedNode()
{
Stack<Node> stk = new Stack<Node>();
stk.Push(this);
Node biggest = null;
while(stk.Any())
{
var node = stk.Pop();
biggest = biggest == null
? node
: (node.words.Count > biggest.words.Count
? node
: biggest);
foreach(var next in node.edges.Where(e=>e != null))
{
stk.Push(next);
}
}
return biggest;
}
public IEnumerable<string> Search(string numberSequenceString)
{
var numberSequence = numberSequenceString
.Select(n => int.Parse(n.ToString()));
return Search(numberSequence);
}
private IEnumerable<string> Search(IEnumerable<int> numberSequence)
{
if(!numberSequence.Any())
{
return words;
}
var first = numberSequence.First();
var remaining = numberSequence.Skip(1);
var nextNode = edges[first];
if(nextNode == null)
{
return Enumerable.Empty<string>();
}
return nextNode.Search(remaining);
}
}
There is a number of optimizations you could make to improve the speed:
Adding .* prefix and suffix to your regex pattern is not necessary, because IsMatch will detect a match anywhere in a string
Using a local Dictionary<int,string> for parts of your pattern can be replaced by a static array
Converting digits to ints can be replaced with subtraction
The foreach loop and appending could be replaced by string.Join
Here is how:
private static string[] digitMap = new[] {
""
, "", "[abcABC]", "[defDEF]"
, "[ghiGHI]", "[jklJKL]", "[mnoMNO]"
, "[pqrsPQRS]", "[tuvTUV]", "[wxyzWXYZ]"
};
void bw1_DoWork(object sender, DoWorkEventArgs e) {
try {
MainPage.pattern = string.Join("", DialerText.Select(c => digitMap[c-'0']));
} catch (Exception f) {
// MessageBox.Show(f.Message);
}
}
I suspect the reason for the blocking is that your background worker thread doesn't actually do very much.
I expect the bw1_RunWorkerCompleted method (which gets run on the MAIN thread after the background worker has completed) is far more long-running! Can you move some (all?) of this code into the bw1_DoWork method instead? Obviously "listobj" would have to be accessible to the background thread though - just pass it into your delegate and access it by the DoWorkEventArgs.Argument property for this...
private void dialer_TextChanged(object sender, TextChangedEventArgs e)
{
MainPage.DialerText = dialer.Text;
if(!bw1.IsBusy)
bw1.RunWorkerAsync(listobj);
}
void bw1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
var digitMap = new Dictionary<int, string>() {
{ 1, "" },
{ 2, "[abcABC]" },
{ 3, "[defDEF]" },
{ 4, "[ghiGHI]" },
{ 5, "[jklJKL]" },
{ 6, "[mnoMNO]" },
{ 7, "[pqrsPQRS]" },
{ 8, "[tuvTUV]" },
{ 9, "[wxyzWXYZ]" },
{ 0, "" },
};
var enteredDigits = DialerText;
var charsAsInts = enteredDigits.ToCharArray().Select(x => int.Parse(x.ToString()));
var regexBuilder = new StringBuilder();
foreach (var val in charsAsInts)
regexBuilder.Append(digitMap[val]);
MainPage.pattern = regexBuilder.ToString();
MainPage.pattern = ".*" + MainPage.pattern + ".*";
var listobj = (ListObjectType)e.Argument;
e.Result = listobj.FindAll(x => x.PhoneNumbers.Any(a=>a.Contains(MainPage.DialerText)) | Regex.IsMatch(x.FirstName, MainPage.pattern));
}
catch (Exception f)
{
// MessageBox.Show(f.Message);
}
}
void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SearchListbox.ItemsSource = (IEnumerable<ListObjectItemType>)e.Result;
}
NB - you'll obviously need to replace the casts to ListObjectType, and ListObjectItemType with the actual types!

Checking for winner in TicTacToe?

What would be the best way to see (in a 2 player) game of Tic Tac Toe who won? Right now I'm using something similar to the following:
if (btnOne.Text == "X" && btnTwo.Text == "X" && btnThree.Text == "X")
{
MessageBox.Show("X has won!", "X won!");
return;
}
else
// I'm not going to write the rest but it's really just a bunch
// if statements.
So how do I get rid of the multiple if's?
Something alongs:
rowSum == 3 || columnSum == 3 || diagnolSum == 3
.. ?
If you store your buttons in a multidimenstional array, you can write some extension methods to get the rows, columns and diagonals.
public static class MultiDimensionalArrayExtensions
{
public static IEnumerable<T> Row<T>(this T[,] array, int row)
{
var columnLower = array.GetLowerBound(1);
var columnUpper = array.GetUpperBound(1);
for (int i = columnLower; i <= columnUpper; i++)
{
yield return array[row, i];
}
}
public static IEnumerable<T> Column<T>(this T[,] array, int column)
{
var rowLower = array.GetLowerBound(0);
var rowUpper = array.GetUpperBound(0);
for (int i = rowLower; i <= rowUpper; i++)
{
yield return array[i, column];
}
}
public static IEnumerable<T> Diagonal<T>(this T[,] array,
DiagonalDirection direction)
{
var rowLower = array.GetLowerBound(0);
var rowUpper = array.GetUpperBound(0);
var columnLower = array.GetLowerBound(1);
var columnUpper = array.GetUpperBound(1);
for (int row = rowLower, column = columnLower;
row <= rowUpper && column <= columnUpper;
row++, column++)
{
int realColumn = column;
if (direction == DiagonalDirection.DownLeft)
realColumn = columnUpper - columnLower - column;
yield return array[row, realColumn];
}
}
public enum DiagonalDirection
{
DownRight,
DownLeft
}
}
And if you use a TableLayoutPanel with 3 rows and 3 columns, you can easily create your buttons programmably and store it into a Button[3, 3] array.
Button[,] gameButtons = new Button[3, 3];
for (int row = 0; column <= 3; row++)
for (int column = 0; column <= 3; column++)
{
Button button = new Button();
// button...
gameLayoutPanel.Items.Add(button);
gameButtons[row, column] = button;
}
And to check for a winner:
string player = "X";
Func<Button, bool> playerWin = b => b.Value == player;
gameButtons.Row(0).All(playerWin) ||
// ...
gameButtons.Column(0).All(playerWin) ||
// ...
gameButtons.Diagonal(DiagonalDirection.DownRight).All(playerWin) ||
// ...
Another simple way out would be to save the winnable positions as a data in an array and use a loop to check all possible winning conditions instead of multiple ifs statements
// winnable positions
var winnables = new[] {
"012",
"345",
"678",
"036",
"147",
"258",
"048",
"246"
};
// extracted from btnOne Two Three....
var gameState = new[] { "X", "O", "X", "whatever" };
string winner = null;
// check each winnable positions
foreach (var position in winnables) {
var pos1 = int.Parse(position[0].ToString());
var pos2 = int.Parse(position[1].ToString());
var pos3 = int.Parse(position[2].ToString());
if (gameState[pos1] == gameState[pos2] &&
gameState[pos2] == gameState[pos3])
winner = gameState[pos1];
}
// do we have a winner?
if (!string.IsNullOrEmpty(winner))
/* we've got a winner */
Basically, don't use btnOne btnTwo btnThree, use a proper array of Buttons or an array that saves the game state in a more accessible format and it'll be easier to compute.
I tend to do things like this:
bool x_wins =
Enumerable
.Range(0, 3)
.SelectMany(i => new Func<int, string>[] { x => array[i, x], x => array[x, i] })
.Concat(new Func<int, string>[] { x => array[x, x], x => array[2 - x, x], })
.Where(f => String.Concat(Enumerable.Range(0, 3).Select(x => f(x))) == "XXX")
.Any();
I know you are no longer looking for an answer to this question. That said, someone might.
Using #fran-casadome's answer and #chakrit's answer, I would do something like this. Hard-coded possibilities seem appropriate. Linq let's up wrap the logic in fluent steps. A nice use.
private bool IsWinner(char player) => new[]
{
new[] { 0, 1, 2 },
new[] { 3, 4, 5 },
new[] { 6, 7, 8 },
new[] { 0, 3, 6 },
new[] { 1, 4, 7 },
new[] { 2, 5, 8 },
new[] { 0, 4, 8 },
new[] { 2, 4, 6 }
}.Any(indexes => indexes.All(index => _data[index] == player));
Here's the rest, for context.
private readonly char[] _data =
new[] { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
public bool GameOver { get; private set; } = false;
public char? WinningPlayer { get; private set; } = null;
public char CurrentPlayer { get; private set; } = 'x';
public void Play(int position)
{
var index = Array.IndexOf(_data, position);
if (GameOver || index == -1)
{
return;
}
if (GameOver = IsWinner(_data[index] = CurrentPlayer))
{
WinningPlayer = CurrentPlayer;
}
else
{
CurrentPlayer = CurrentPlayer == 'x' ? 'o' : 'x';
}
}

C# Permutation of an array of arraylists?

I have an ArrayList[] myList and I am trying to create a list of all the permutations of the values in the arrays.
EXAMPLE: (all values are strings)
myList[0] = { "1", "5", "3", "9" };
myList[1] = { "2", "3" };
myList[2] = { "93" };
The count of myList can be varied so its length is not known beforehand.
I would like to be able to generate a list of all the permutations similar to the following (but with some additional formatting).
1 2 93
1 3 93
5 2 93
5 3 93
3 2 93
3 3 93
9 2 93
9 3 93
Does this make sense of what I am trying to accomplish? I can't seem to come up with a good method for doing this, (if any).
Edit:
I am not sure if recursion would interfere with my desire to format the output in my own manner. Sorry I did not mention before what my formatting was.
I want to end up building a string[] array of all the combinations that follows the format like below:
for the "1 2 93" permutation
I want the output to be "val0=1;val1=2;val2=93;"
I will experiment with recursion for now. Thank you DrJokepu
I'm surprised nobody posted the LINQ solution.
from val0 in new []{ "1", "5", "3", "9" }
from val1 in new []{ "2", "3" }
from val2 in new []{ "93" }
select String.Format("val0={0};val1={1};val2={2}", val0, val1, val2)
Recursive solution
static List<string> foo(int a, List<Array> x)
{
List<string> retval= new List<string>();
if (a == x.Count)
{
retval.Add("");
return retval;
}
foreach (Object y in x[a])
{
foreach (string x2 in foo(a + 1, x))
{
retval.Add(y.ToString() + " " + x2.ToString());
}
}
return retval;
}
static void Main(string[] args)
{
List<Array> myList = new List<Array>();
myList.Add(new string[0]);
myList.Add(new string[0]);
myList.Add(new string[0]);
myList[0] = new string[]{ "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
foreach (string x in foo(0, myList))
{
Console.WriteLine(x);
}
Console.ReadKey();
}
Note that it would be pretty easy to return a list or array instead of a string by changing the return to be a list of lists of strings and changing the retval.add call to work with a list instead of using concatenation.
How it works:
This is a classic recursive algorithm. The base case is foo(myList.Count, myList), which returns a List containing one element, the empty string. The permutation of a list of n string arrays s1, s2, ..., sN is equal to every member of sA1 prefixed to the permutation of n-1 string arrays, s2, ..., sN. The base case is just there to provide something for each element of sN to be concatenated to.
I recently ran across a similar problem in a project of mine and stumbled on this question. I needed a non-recursive solution that could work with lists of arbitrary objects. Here's what I came up with. Basically I'm forming a list of enumerators for each of the sub-lists and incrementing them iteratively.
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<IEnumerable<T>> lists)
{
// Check against an empty list.
if (!lists.Any())
{
yield break;
}
// Create a list of iterators into each of the sub-lists.
List<IEnumerator<T>> iterators = new List<IEnumerator<T>>();
foreach (var list in lists)
{
var it = list.GetEnumerator();
// Ensure empty sub-lists are excluded.
if (!it.MoveNext())
{
continue;
}
iterators.Add(it);
}
bool done = false;
while (!done)
{
// Return the current state of all the iterator, this permutation.
yield return from it in iterators select it.Current;
// Move to the next permutation.
bool recurse = false;
var mainIt = iterators.GetEnumerator();
mainIt.MoveNext(); // Move to the first, succeeds; the main list is not empty.
do
{
recurse = false;
var subIt = mainIt.Current;
if (!subIt.MoveNext())
{
subIt.Reset(); // Note the sub-list must be a reset-able IEnumerable!
subIt.MoveNext(); // Move to the first, succeeds; each sub-list is not empty.
if (!mainIt.MoveNext())
{
done = true;
}
else
{
recurse = true;
}
}
}
while (recurse);
}
}
You could use factoradics to generate the enumeration of permutations. Try this article on MSDN for an implementation in C#.
This will work no matter how many arrays you add to your myList:
static void Main(string[] args)
{
string[][] myList = new string[3][];
myList[0] = new string[] { "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
List<string> permutations = new List<string>(myList[0]);
for (int i = 1; i < myList.Length; ++i)
{
permutations = RecursiveAppend(permutations, myList[i]);
}
//at this point the permutations variable contains all permutations
}
static List<string> RecursiveAppend(List<string> priorPermutations, string[] additions)
{
List<string> newPermutationsResult = new List<string>();
foreach (string priorPermutation in priorPermutations)
{
foreach (string addition in additions)
{
newPermutationsResult.Add(priorPermutation + ":" + addition);
}
}
return newPermutationsResult;
}
Note that it's not really recursive. Probably a misleading function name.
Here is a version that adheres to your new requirements. Note the section where I output to console, this is where you can do your own formatting:
static void Main(string[] args)
{
string[][] myList = new string[3][];
myList[0] = new string[] { "1", "5", "3", "9" };
myList[1] = new string[] { "2", "3" };
myList[2] = new string[] { "93" };
List<List<string>> permutations = new List<List<string>>();
foreach (string init in myList[0])
{
List<string> temp = new List<string>();
temp.Add(init);
permutations.Add(temp);
}
for (int i = 1; i < myList.Length; ++i)
{
permutations = RecursiveAppend(permutations, myList[i]);
}
//at this point the permutations variable contains all permutations
foreach (List<string> list in permutations)
{
foreach (string item in list)
{
Console.Write(item + ":");
}
Console.WriteLine();
}
}
static List<List<string>> RecursiveAppend(List<List<string>> priorPermutations, string[] additions)
{
List<List<string>> newPermutationsResult = new List<List<string>>();
foreach (List<string> priorPermutation in priorPermutations)
{
foreach (string addition in additions)
{
List<string> priorWithAddition = new List<string>(priorPermutation);
priorWithAddition.Add(addition);
newPermutationsResult.Add(priorWithAddition);
}
}
return newPermutationsResult;
}
What you are asking for is called the Cartesian Product. Once you know what its called, there are several similar questions on Stack Overflow. They all seem to end up pointing to an answer which ended up written as a blog post:
http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
Non-recursive solution:
foreach (String s1 in array1) {
foreach (String s2 in array2) {
foreach (String s3 in array3) {
String result = s1 + " " + s2 + " " + s3;
//do something with the result
}
}
}
Recursive solution:
private ArrayList<String> permute(ArrayList<ArrayList<String>> ar, int startIndex) {
if (ar.Count == 1) {
foreach(String s in ar.Value(0)) {
ar.Value(0) = "val" + startIndex + "=" + ar.Value(0);
return ar.Value(0);
}
ArrayList<String> ret = new ArrayList<String>();
ArrayList<String> tmp1 ar.Value(0);
ar.remove(0);
ArrayList<String> tmp2 = permute(ar, startIndex+1);
foreach (String s in tmp1) {
foreach (String s2 in tmp2) {
ret.Add("val" + startIndex + "=" + s + " " + s2);
}
}
return ret;
}
Here is a generic recursive function that I wrote (and an overload that may be convenient to call):
Public Shared Function GetCombinationsFromIEnumerables(ByRef chain() As Object, ByRef IEnumerables As IEnumerable(Of IEnumerable(Of Object))) As List(Of Object())
Dim Combinations As New List(Of Object())
If IEnumerables.Any Then
For Each v In IEnumerables.First
Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(New Object() {v}).ToArray, IEnumerables.Skip(1)).ToArray)
Next
Else
Combinations.Add(chain)
End If
Return Combinations
End Function
Public Shared Function GetCombinationsFromIEnumerables(ByVal ParamArray IEnumerables() As IEnumerable(Of Object)) As List(Of Object())
Return GetCombinationsFromIEnumerables(chain:=New Object() {}, IEnumerables:=IEnumerables.AsEnumerable)
End Function
And the equivalent in C#:
public static List<object[]> GetCombinationsFromIEnumerables(ref object[] chain, ref IEnumerable<IEnumerable<object>> IEnumerables)
{
List<object[]> Combinations = new List<object[]>();
if (IEnumerables.Any) {
foreach ( v in IEnumerables.First) {
Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(new object[] { v }).ToArray, IEnumerables.Skip(1)).ToArray);
}
} else {
Combinations.Add(chain);
}
return Combinations;
}
public static List<object[]> GetCombinationsFromIEnumerables(params IEnumerable<object>[] IEnumerables)
{
return GetCombinationsFromIEnumerables(chain = new object[], IEnumerables = IEnumerables.AsEnumerable);
}
Easy to use:
Dim list1 = New String() {"hello", "bonjour", "hallo", "hola"}
Dim list2 = New String() {"Erwin", "Larry", "Bill"}
Dim list3 = New String() {"!", ".."}
Dim result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3)
For Each r In result
Debug.Print(String.Join(" "c, r))
Next
or in C#:
object list1 = new string[] {"hello","bonjour","hallo","hola"};
object list2 = new string[] {"Erwin", "Larry", "Bill"};
object list3 = new string[] {"!",".."};
object result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3);
foreach (r in result) {
Debug.Print(string.Join(' ', r));
}
Here is a version which uses very little code, and is entirely declarative
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> collection) where T : IComparable
{
if (!collection.Any())
{
return new List<IEnumerable<T>>() {Enumerable.Empty<T>() };
}
var sequence = collection.OrderBy(s => s).ToArray();
return sequence.SelectMany(s => GetPermutations(sequence.Where(s2 => !s2.Equals(s))).Select(sq => (new T[] {s}).Concat(sq)));
}
class Program
{
static void Main(string[] args)
{
var listofInts = new List<List<int>>(3);
listofInts.Add(new List<int>{1, 2, 3});
listofInts.Add(new List<int> { 4,5,6 });
listofInts.Add(new List<int> { 7,8,9,10 });
var temp = CrossJoinLists(listofInts);
foreach (var l in temp)
{
foreach (var i in l)
Console.Write(i + ",");
Console.WriteLine();
}
}
private static IEnumerable<List<T>> CrossJoinLists<T>(IEnumerable<List<T>> listofObjects)
{
var result = from obj in listofObjects.First()
select new List<T> {obj};
for (var i = 1; i < listofObjects.Count(); i++)
{
var iLocal = i;
result = from obj in result
from obj2 in listofObjects.ElementAt(iLocal)
select new List<T>(obj){ obj2 };
}
return result;
}
}
Here's a non-recursive, non-Linq solution. I can't help feeling like I could have less looping and calculate the positions with division and modulo, but can't quite wrap my head around that.
static void Main(string[] args)
{
//build test list
List<string[]> myList = new List<string[]>();
myList.Add(new string[0]);
myList.Add(new string[0]);
myList.Add(new string[0]);
myList[0] = new string[] { "1", "2", "3"};
myList[1] = new string[] { "4", "5" };
myList[2] = new string[] { "7", "8", "9" };
object[][] xProds = GetProducts(myList.ToArray());
foreach(object[] os in xProds)
{
foreach(object o in os)
{
Console.Write(o.ToString() + " ");
}
Console.WriteLine();
}
Console.ReadKey();
}
static object[][] GetProducts(object[][] jaggedArray){
int numLists = jaggedArray.Length;
int nProducts = 1;
foreach (object[] oArray in jaggedArray)
{
nProducts *= oArray.Length;
}
object[][] productAry = new object[nProducts][];//holds the results
int[] listIdxArray = new int[numLists];
listIdxArray.Initialize();
int listPtr = 0;//point to current list
for(int rowcounter = 0; rowcounter < nProducts; rowcounter++)
{
//create a result row
object[] prodRow = new object[numLists];
//get values for each column
for(int i=0;i<numLists;i++)
{
prodRow[i] = jaggedArray[i][listIdxArray[i]];
}
productAry[rowcounter] = prodRow;
//move the list pointer
//possible states
// 1) in a list, has room to move down
// 2) at bottom of list, can move to next list
// 3) at bottom of list, no more lists left
//in a list, can move down
if (listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
{
listIdxArray[listPtr]++;
}
else
{
//can move to next column?
//move the pointer over until we find a list, or run out of room
while (listPtr < numLists && listIdxArray[listPtr] >= (jaggedArray[listPtr].Length - 1))
{
listPtr++;
}
if (listPtr < listIdxArray.Length && listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
{
//zero out the previous stuff
for (int k = 0; k < listPtr; k++)
{
listIdxArray[k] = 0;
}
listIdxArray[listPtr]++;
listPtr = 0;
}
}
}
return productAry;
}
One of the problems I encountred when I was doing this for a very large amount of codes was that with the example brian was given I actually run out of memory. To solve this I used following code.
static void foo(string s, List<Array> x, int a)
{
if (a == x.Count)
{
// output here
Console.WriteLine(s);
}
else
{
foreach (object y in x[a])
{
foo(s + y.ToString(), x, a + 1);
}
}
}
static void Main(string[] args)
{
List<Array> a = new List<Array>();
a.Add(new string[0]);
a.Add(new string[0]);
a.Add(new string[0]);
a[0] = new string[] { "T", "Z" };
a[1] = new string[] { "N", "Z" };
a[2] = new string[] { "3", "2", "Z" };
foo("", a, 0);
Console.Read();
}
private static void GetP(List<List<string>> conditions, List<List<string>> combinations, List<string> conditionCombo, List<string> previousT, int selectCnt)
{
for (int i = 0; i < conditions.Count(); i++)
{
List<string> oneField = conditions[i];
for (int k = 0; k < oneField.Count(); k++)
{
List<string> t = new List<string>(conditionCombo);
t.AddRange(previousT);
t.Add(oneField[k]);
if (selectCnt == t.Count )
{
combinations.Add(t);
continue;
}
GetP(conditions.GetRange(i + 1, conditions.Count - 1 - i), combinations, conditionCombo, t, selectCnt);
}
}
}
List<List<string>> a = new List<List<string>>();
a.Add(new List<string> { "1", "5", "3", "9" });
a.Add(new List<string> { "2", "3" });
a.Add(new List<string> { "93" });
List<List<string>> result = new List<List<string>>();
GetP(a, result, new List<string>(), new List<string>(), a.Count);
Another recursive function.

Categories