Here is the code:
class Program
{
static void Main(string[] args)
{
List<Item> cont1 = new List<Item>();
cont1.Add(objA); //objA is local varible that has been defined.
cont1.Add(objB); //objB is local varible that has been defined.
cont1.Add(objC); //objC is local varible that has been defined.
cont1.Add(objD); //objD is local varible that has been defined.
cont1.Add(objE); //objE is local varible that has been defined.
int count = cont1.Count;
List<Item> cont2 = GroupingA(cont1, count);
for (int i = 0; i < cont1.Count; i++)
{
Console.Write(cont1[i].Name + " ");//output the item's name.
}
Console.WriteLine();
Console.Write("Container 2: ");
for (int i = 0; i < cont2.Count; i++)
{
Console.Write(cont2[i].Name + " ");//output the item's name.
}
}
}
public class GroupItem
{
public List<Item> GroupingA (List<Item> obj, int count)
{
List<Item> temp = new List<Item>();
for (int i = 0; i < count; i++)
{
if (i == count - 1)
{
break;
}
else if (temp.Count > 0 )
{
break;
}
else
{
for (int j = i + 1; j < count; j++)
{
bool equal = obj[i].EqualFirstPhase(obj[j]);
if (equal == true)
{
if (temp.Exists(element => element == temp[j]))
{
continue;
}
else
{
temp.Add(obj[j]);
if (temp.Exists(element => element == obj[i]))
{
continue;
}
else
{
temp.Insert(0, obj[i]);
}
i--;
}
}
}
}
for (int k = 0; k < count; k++)
{
for (int l = 0; l < temp.Count; l++)
{
if (obj[k].Name.Contains(temp[l].Name))
{
obj.RemoveAt(k);
count--;
}
}
if (obj.Count < count)
{
k = 0;
}
}
}
return temp;
}
}
I want to use GroupingA method to regroup the cont1 into cont2. However, there is an error.
The name 'GroupingA ' does not exist in the current context.
Anyone can help me??? Really weak in OOP, especially naming.
YOu need to use :-
GroupItem grpItem = new GroupItem();
List<Item> cont2 = grpItem.GroupingA(cont1, count);
Reason:-
Your GroupingA method is non-static and defined in the class GroupingItem. And you are trying to access it from your Program class as if the method GroupingA is a part of that class. For accessing non-static methods from other classes you need to Instantiate that class and use that object to get access to the class. In case of static method you can directly access them with the . operator on that particular class. ex Class.Method(...)
The line
List<Item> cont2 = GroupingA(cont1, count); is being called in the class Program.
Without a class name or object identifier that says where a method is located, it will look in the current class, which in your case is Program.
You have several choices.
Make the GroupingA method static and replace the line with List<Item> cont2 = GroupItem.GroupingA(cont1, count);
Make an instance of GroupItem and refer to that instead:
GroupItem g = new GroupItem();
List<Item> cont2 = your.GroupingA(cont1, count);
Move the method GroupingA out of the GroupItem class and place it within the Program class so your line knows where to find it.
Related
How to save user input into an array
I have two modules
MODULE director: Allows you to add and remove teachers.
MODULE Informer: Gives information about the teachers available in the school.
All this in an endless loop.
To the code: I have an initial array of teachersForDirector, consisting of 10 teachers. If the user wants to add or remove a teacher, I use the DeletingTeachers, AddingTeachers methods.
The problem is that when I select the "informer" module, the values of the teachersForDirector array are reset to the original.
Code:
public static List<string> DeletingTeachers(List<string> arrayTeachers)
{
int counter = 0;
Console.WriteLine("which teacher to remove? [index]");
for (int i = 0; i < arrayTeachers.Count; i++)
{
Console.WriteLine($"teacher with number - {counter} {arrayTeachers[i]}");
counter++;
}
int index = int.Parse(Console.ReadLine());
arrayTeachers.RemoveAt(index);
Console.Clear();
for (int i = 0; i < arrayTeachers.Count; i++)
{
Console.WriteLine($"new teachers - {arrayTeachers[i]}");
}
return arrayTeachers;
}
public static List<string> AddingTeachers(List<string> arrayTeachers)
{
Console.WriteLine("enter the name of the new teacher");
arrayTeachers.Add(Console.ReadLine());
for (int i = 0; i < arrayTeachers.Count; i++)
{
Console.WriteLine($"{arrayTeachers[i]}");
}
Console.Clear();
Console.WriteLine("teachers information:");
for (int i = 0; i < arrayTeachers.Count; i++)
{
Console.WriteLine($"{arrayTeachers[i]}");
}
return arrayTeachers;
}
static void Main(string[] args)
{
while (true)
{
List<string> teachersForDirector = new List<string> { "Матвеева Н.В", "Ивашина А.С", "Изюмов Р.Н.", "Жиделев А.С.", "Карпов М.Д", "Петрова О.А", "Таран Г.Г.", "Овчарова Д.Е.", "Андреев Д.Е.", "Долгих Н.О." };
Console.WriteLine("Choose:\ndirector - 0 \ninformer - 1"); // MAIN MENU
int DirectorZeroInformerOne = int.Parse(Console.ReadLine());
Console.Clear();
if (DirectorZeroInformerOne == 0) // changing teachers
{
{
Console.WriteLine("вы хотите удалить учителя[1] или добавить нового[2]?");
int chooseDeleteOrNew = int.Parse(Console.ReadLine());
Console.Clear();
if (chooseDeleteOrNew == 1) // removing a teacher
{
DeletingTeachers(teachersForDirector);
}
if (chooseDeleteOrNew == 2) // adding a teacher
{
AddingTeachers(teachersForDirector);
}
}
}
if (DirectorZeroInformerOne == 1)
{
Console.WriteLine("information about teachers");
for (int i = 0; i < teachersForDirector.Count; i++)
{
Console.WriteLine(teachersForDirector[i]);
}
}
}
}
How do I make sure that the changed data is saved and the informer module outputs the correct information?
Say I have a GameObject array with child objects inside of it:
GameObjects = new List<GameObject>
{
new Tile(0, 0, new int[] { 1, 2, 3, 0 }),
new BuyTile(1, 0),
new BuyTile(0, 1),
new BuyTile(-1, 0),
new BuyTile(0, -1)
};
And I want to access a property in a Tile object in this array.
public void UpdateResources()
{
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile)
{
/* I want to read a property of the Tile here, and it's not in the abstract class
* GameObject.
*/
}
}
}
How do I do so?
I couldn't find anything myself about this issue, but if someone has a link to another related question I will gladly accept it.
public void UpdateResources()
{
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile t)
{
t.X // <- read property
}
}
}
You can use as operator and null check:
for (int i = 0; i < GameObjects.Count; i++)
{
var tile = GameObjects[i] as Tile;
if (tile != null)
{
// use tile
}
}
If your version of unity supports C# 7.0 you can use is operator with the type pattern:
for (int i = 0; i < GameObjects.Count; i++)
{
if (GameObjects[i] is Tile tile)
{
// use tile
}
}
You can try Linq:
public void UpdateResources() {
foreach (Tile tile in GameObjects.OfType<Tile>()) {
//TODO: put relevant code here, e.g.
// tile.SomeProperty = tile.SomeProperty - 5;
}
}
I have a program which builds a very large tree from input data and traverses it, both by recursion. I have tested the program on smaller inputs (and thus smaller trees) and it functions as intended. However when the input data is much larger i run into 'Process is terminated due to StackOverflowException'. I assume this is due to the stack running out of space. Is there any way to prevent this or do I have to switch to building the tree via iteration instead? Or perhaps I am missing a case of infinite recursion somewhere?
Here is the code:
class Program
{
static int[] tileColors;
static Color[] colors;
static int totalTiles;
static void Main(string[] args)
{
Stopwatch s = new Stopwatch();
s.Start();
string[] data = File.ReadAllLines("colors.txt");
totalTiles = int.Parse(data[0].Split(' ')[0]);
int totalColors = int.Parse(data[0].Split(' ')[1]);
string[] colorsRaw = data[1].Split(' ');
tileColors = new int[totalTiles];
for (int i = 0; i < totalTiles; i++)
{
tileColors[i] = int.Parse(colorsRaw[i]) - 1;
}
colors = new Color[totalColors];
for (int i = 3; i < data.Length; i++)
{
string[] raw = data[i].Split(' ');
int[] pair = new int[] { int.Parse(raw[0]) - 1, int.Parse(raw[1]) - 1 };
if (colors[pair[0]] == null)
colors[pair[0]] = new Color(pair[1]);
else
colors[pair[0]].pairs.Add(pair[1]);
if (colors[pair[1]] == null)
colors[pair[1]] = new Color(pair[0]);
else
colors[pair[1]].pairs.Add(pair[0]);
}
Tree t = new Tree();
t.root = new Node(0);
PopulateTree(t.root);
long ans = t.CountMatchingLeaves(t.root, totalTiles - 1) % 1000000007;
Console.WriteLine(ans);
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
static void PopulateTree(Node root)
{
for (int i = root.tile + 1; i < totalTiles; i++)
{
if (colors[tileColors[i]] == null) continue;
if (colors[tileColors[i]].Compatible(tileColors[root.tile]))
{
var node = new Node(i);
root.children.Add(node);
PopulateTree(node);
}
}
}
}
class Color
{
public List<int> pairs = new List<int>();
public Color(int pair)
{
pairs.Add(pair);
}
public bool Compatible(int c)
{
return pairs.Contains(c);
}
}
class Node
{
public List<Node> children = new List<Node>();
public int tile;
public Node(int tile)
{
this.tile = tile;
}
}
class Tree
{
public Node root;
public List<Node> GetMatchingLeaves(Node root, int match)
{
if (root.children.Count == 0)
{
if (root.tile == match)
{
return new List<Node>() { root };
}
return new List<Node>();
}
List<Node> list = new List<Node>();
foreach(var c in root.children)
{
list.AddRange(GetMatchingLeaves(c, match));
}
return list;
}
public long CountMatchingLeaves(Node root, int match)
{
if (root.children.Count == 0)
{
if (root.tile == match)
{
return 1;
}
return 0;
}
long count = 0;
foreach (var c in root.children)
{
count += CountMatchingLeaves(c, match);
}
return count;
}
}
You can always rewrite recursion as iteration, usually by using a stack class rather than rely on your thread's stack. For your code it would look like this:
static void PopulateTree(Node start)
{
var nodes = new Stack<Node>();
nodes.Push(start);
while(nodes.Count != 0)
{
var root = nodes.Pop();
for (int i = root.tile + 1; i < totalTiles; i++)
{
if (colors[tileColors[i]] == null) continue;
if (colors[tileColors[i]].Compatible(tileColors[root.tile]))
{
var node = new Node(i);
root.children.Add(node);
nodes.Push(node);
}
}
}
}
The while loop checking for more items is the equivalent of your terminating condition in recursion.
I have a problem that I really cannot get my head around. I know how to sort data in general but this one is taxing me!
I have a list of values in an array. The values look like this:
[03;02HTransactions
[03;16HPost Transactions
[04:02HDividends
[04;16HPostDividends
[01:01H-----------------------------------------------------
[05:01H-----------------------------------------------------
[02:16HDate: Today
[02:02HTrades
So its essentially ANSI formatting from a terminal screen which i'm trying to re-construct into a list so that I can print it on our test logs so it at least looks vaguely readable.
So this is how it works within the first 6 characters: [XX:YY where XX is the row number and YY is the column number. The H doesn't matter its just formatting.
Here is what I've got so far:
List<string> rows = new List<string>();
for (int i = 0; i <= filteredLines.Count - 1; i++)
{
int rowIndex = Convert.ToInt32(filteredLines[i].Substring(1, 2));
Dictionary<int, string> columns = new Dictionary<int, string>();
foreach (string row in filteredLines)
{
int innerRowIndex = Convert.ToInt32(row.Substring(1, 2));
if (innerRowIndex == rowIndex)
{
int columnIndex = Convert.ToInt32(filteredLines[i].Substring(4, 2));
string value = filteredLines[i].Remove(0, 7);
columns.Add(columnIndex, value);
}
}
string columnConcatenated = "";
for (int j = 0; j <= columns.Count; j ++ )
{
columnConcatenated = columnConcatenated + columns[j];
}
rows.Add(columnConcatenated);
}
What I essentially want to do is to to build up the lines and sort them into a list based on the row number so it looks like:
--------------------------------------------
Trades Date: Today
Transactions Post Transactions
Dividends Post Dividends
--------------------------------------------
my example isn't 100% accurate as its hard to count the exact columns, but you get the idea. They just need to be on the same line in the correct order.
I cant help but feel i'm probably not going about this the best way. So is there an ideal way for me to achieve this?
Okay, I would implement it like so:
Create a simple POCO/class to represent a log entry with the properties row, column and text
Implement the IComparable interface, so these items can be sorted, on row # first and on column # second
Parse every log line and create a simple POCO Entry object for each
Use a simple List<Entry> and sort it afterwards
Use a StringBuilder to build up the final output
Loop over every Entry in the list, checking it's row # and perhaps entering some newlines for our StringBuilder if there are gaps
If we get an Entry with a row number which is the same as a previous one (which you can use a temp variable for), don't output a newline, but append the Entry.text to this line instead, at the column you want
You already have code to parse each line, extracting its row, column, and displayed text. If the lines of text are not sparse, you could represent this as basically a 2D dynamic array of characters that automatically pads itself out with spaces or empty lines, like so:
public class StringBuilderList : IList<string>
{
readonly List<StringBuilder> list = new List<StringBuilder>();
readonly char pad = ' ';
const char DefaultPad = ' ';
public StringBuilderList(char pad)
{
this.pad = pad;
}
public StringBuilderList() : this(DefaultPad) {}
public void SetString(int iLine, int iChar, string text)
{
list.EnsureCount(iLine + 1);
if (list[iLine] == null)
list[iLine] = new StringBuilder(iChar + text.Length);
var sb = list[iLine];
sb.OverwriteAt(iChar, text, pad);
}
#region IList<string> Members
public int IndexOf(string item)
{
for (int i = 0; i < Count; i++)
if (this[i] == item) // this is not memory-efficient.
return i;
return -1;
}
public void Insert(int index, string item)
{
var sb = new StringBuilder(item);
list.Insert(index, sb);
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public string this[int index]
{
get
{
// Hide the nulls from the caller!
var sb = list[index];
if (sb == null)
return string.Empty;
return sb.ToString();
}
set
{
if (string.IsNullOrEmpty(value))
{
if (list[index] != null)
list[index].Length = 0;
}
else if (list[index] == null)
{
list[index] = new StringBuilder(value);
}
else
{
list[index].Length = 0;
list[index].Append(value);
}
}
}
#endregion
#region ICollection<string> Members
public void Add(string item)
{
list.Add(new StringBuilder(item));
}
public void Clear()
{
list.Clear();
}
public bool Contains(string item)
{
return IndexOf(item) >= 0;
}
public void CopyTo(string[] array, int arrayIndex)
{
foreach (var str in this)
array[arrayIndex++] = str;
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(string item)
{
int index = IndexOf(item);
if (index < 0)
return false;
RemoveAt(index);
return true;
}
#endregion
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
foreach (var sb in list)
yield return (sb == null ? string.Empty : sb.ToString());
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
SetString is the method you would use, it copies the string into the 2d array of characters, expanding it as required with empty lines and/or space characters.
And helper methods:
public static class ListHelper
{
public static void Resize<T>(this List<T> list, int count)
{
if (list == null || count < 0)
throw new ArgumentException();
int oldCount = list.Count;
if (count > oldCount)
{
list.Capacity = count;
for (int i = oldCount; i < count; i++)
list.Add(default(T));
}
else if (count < oldCount)
{
for (int i = oldCount-1; i >= count; i--)
list.RemoveAt(i);
}
}
public static void EnsureCount<T>(this List<T> list, int count)
{
if (list == null || count < 0)
throw new ArgumentException();
if (count > list.Count)
list.Resize(count);
}
}
public static class StringBuilderHelper
{
public static void OverwriteAt(this StringBuilder sb, int index, string text, char pad)
{
var textLen = text.Length;
if (textLen + index > sb.Length)
{
for (int i = sb.Length, newLen = textLen + index; i < newLen; i++)
{
sb.Append(pad);
}
}
for (int i = 0; i < textLen; i++)
{
sb[index + i] = text[i];
}
}
}
So a few people have some solutions though they seemed a bit over complicated for what I needed. I managed to resolve the issue myself using a pen and paper then trying it in visual studio. Here is what I did:
First I created a list by looking through the original array and I sorted and removed duplicates:
List<int> rowList = new List<int>();
for (int i = 0; i <= filteredLines.Count - 1; i++)
{
int rowIndex = Convert.ToInt32(filteredLines[i].Substring(1, 2));
rowList.Add(rowIndex);
}
rowList = rowList.Distinct().ToList<int>();
rowList.Sort();
Next I created a container for my final list that would hold the values, then I ran my sorting routine which makes use of a SortedList in order to ensure the columns are sorted before I concatenate them:
foreach (int listRow in rowList)
{
SortedList<int, string> columnList = new SortedList<int, string>();
foreach(string row in filteredLines)
{
int rowIndex = Convert.ToInt32(row.Substring(1, 2));
if(rowIndex==listRow)
{
int columnIndex = Convert.ToInt32(row.Substring(4, 2));
string value = row.Remove(0, 7);
if(columnList.ContainsKey(columnIndex))
{
columnList[columnIndex] = columnList[columnIndex] + value;
}
else
{
columnList.Add(columnIndex, value);
}
}
}
string concatenatedColumns = "";
foreach(string col in columnList.Values)
{
concatenatedColumns = concatenatedColumns + col;
}
parsedAndSortedRows.Add(concatenatedColumns);
}
It does the job fine and puts all the columns in order on the correct row as I wanted. Thanks for the help to everyone though it was through the different answers I helped come up with this solution.
I Have this problem where I can´t load my data into my TreeView but I have to do it manually instead. My static solution looks like this:
public static ObservableCollection<ClassOfDoom> GetAll()
{
ObservableCollection<ClassOfDoom> listToReturn = new ObservableCollection<ClassOfDoom>();
ClassOfDoom treeItem = null;
OUViewModel ouvm = new OUViewModel();
int[] tempOU = ouvm.HierarchyIntOU;
int[] tempP = ouvm.HierarchyIntParent;
treeItem = new ClassOfDoom("Root");
treeItem.cID = tempOU[0];
treeItem.pID = tempP[0];
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
if (treeItem.cID == tempP[i])
{
treeItem.ClassOfDooms.Add(new ClassOfDoom(tempOU[i].ToString()));
treeItem.ClassOfDooms.Last().pID = tempP[i];
treeItem.ClassOfDooms.Last().cID = tempOU[i];
for (int i1 = 0; i1 < ouvm.HierarchyIntParent.Length; i1++)
{
if (treeItem.ClassOfDooms.Last().cID == tempP[i1])
{
treeItem.ClassOfDooms.Last().Countries.Add(new ClassOfDoom(tempOU[i1].ToString()));
}
}
}
}
listToReturn.Add(treeItem);
return listToReturn;
}
This works but as you can see it´s only three levels and I wan´t a dynamic amount of levels. If someone wonders my ClassOfDooms list looks like this:
public ObservableCollection<ClassOfDoom> ClassOfDooms
{
get
{
if (classOfDooms == null) classOfDooms = new ObservableCollection<ClassOfDoom>();
return classOfDooms;
}
set { classOfDooms = value; }
}
I want to state again that I have no trouble reading data from my database or anything like that. The TreeView get´s the right information just not all of it.
EDIT: I solved it myself like this:
ClassOfDoom[] asdfDooms = new ClassOfDoom[ouvm.HierarchyIntParent.Length];
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
asdfDooms[i] = new ClassOfDoom();
asdfDooms[i].cID = tempOU[i];
asdfDooms[i].pID = tempP[i];
asdfDooms[i].name = tempPersonName + asdfDooms[i].cID.ToString();
}
for (int aint = 0; aint < ouvm.HierarchyIntParent.Length; aint++)
{
for (int i = 0; i < ouvm.HierarchyIntParent.Length; i++)
{
if (asdfDooms[aint].cID == asdfDooms[i].pID)
{
asdfDooms[aint].classOfDooms.Add(asdfDooms[i]);
}
}
}
listToReturn.Add(asdfDooms[0]);
Try implementing the INotifyPropertyChanged interface in conjunction with the HierarchicalDataTemplate control, this should ensure that changes made to the underlying data structure are reflected in the TreeView structure.