Using Lists as method arguments [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am making a basic city builder game (in console). I am having a problem with a method (DrawMap). I cant get the lists to work as input arguments to the method. I get a whole bunch of errors, so here is the code.
EDIT: It works now, thank you kmatyaszek.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace City
{
public class map
{
public int m { get; set; } //Map size
public List<int> info { get; set; }
public List<int> fire { get; set; }
public List<int> police { get; set; }
public List<int> education { get; set; }
public List<int> health { get; set; }
public List<int> cursor { get; set; }
}
class Program
{
static void Main(string[] args)
{
map map1 = new map();
map1.m = 256;
map1.info = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.info.Add(0);
}
map1.fire = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.fire.Add(0);
}
map1.police = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.police.Add(0);
}
map1.education = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.education.Add(0);
}
map1.health = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.health.Add(0);
}
map1.cursor = new List<int>() { 0, 0 };
DrawMap(map1.info, map1.cursor);
}
static void DrawMap(List<int> map1.info, List<int> map1.cursor)
{
int j = 0;
int k = 0;
for (int k = 0; k < Math.Sqrt(map1.m); k++)
{
Console.SetCursorPosition(map1.cursor[j], map1.cursor[k]);
for (int j = 0; j < Math.Sqrt(map1.m); j++)
{
Console.SetCursorPosition(map1.cursor[j], map1.cursor[k]);
Console.Write("A");
}
}
}
}
}

You should read about C# methods (https://msdn.microsoft.com/en-us/library/ms173114.aspx).
I think that method DrawMap should take map object:
...
map1.health = new List<int>();
for (int i = 0; i < map1.m; i++)
{
map1.health.Add(0);
}
map1.cursor = new List<int>() { 0, 0 };
DrawMap(map1);
}
static void DrawMap(map map1)
{
int j = 0;
int k = 0;
for (k = 0; k < Math.Sqrt(map1.m); k++)
{
Console.SetCursorPosition(map1.cursor[j], map1.cursor[k]);
for (j = 0; j < Math.Sqrt(map1.m); j++)
{
Console.SetCursorPosition(map1.cursor[j], map1.cursor[k]);
Console.Write("A");
}
}
}
...
In DrawMap you declare two locals (j and k) in the same scope. You can't do that.
Here you can read about local variable and scope:
https://blogs.msdn.microsoft.com/samng/2007/11/09/local-variable-scoping-in-c/

I don't know where to begin. Let's start with the parameters of the DrawMap method. C# does not allow . in variable names. When you declare the signature of a method you write only names for the parameters. Don't try to reference existing variables in your program. Just choose a name. The compiler will know quick list you mean when you pass them in the call of the method:
DrawMap(map1.info, map.cursor);
After you have given proper names for the parameters of your method like this:
static void DrawMap(List<int> info, List<int> cursor)
You can use the names inside the scope of the method.
The second thing is that you declare your index variables in the method twice. Look at your for-loop declaration. There you have int k=0; k<... that means that a new variable with the same name is declared. Just delete the two variables above the loops.

Related

C# CSV parsing and hiding columns or rows that have true or false value

How to make console app to read csv file that has row IsHidden( isHidden = false for to be shown )
The point is I have made everything up and running but cannot think of the logic for the true(hidden) and false(true) row to be read into console app and shows it those who should :D - sorry for my bad English :)
the code I'm using
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PreInterviewTask
{
class Program
{
static void Main(string[] args)
{
// Get the data from path.
string sampleCSV = #"C:\Users\Tomas\source\repos\PreInterviewTask\PreInterviewTask\HistoricalData\HistoricalData.csv";
string[,] values = LoadCSV(sampleCSV);
int num_rows = values.GetUpperBound(0) + 1;
int num_cols = values.GetUpperBound(1) + 1;
// Display the data to show we have it.
for (int c = 0; c < num_cols; c++)
Console.Write(values[0, c] + "\t");
//Read the data.
for (int r = 1; r < num_rows; r++)
{
// dgvValues.Rows.Add();
Console.WriteLine();
for (int c = 0; c < num_cols; c++)
{
Console.Write(values[r, c] + "\t");
}
}
Console.ReadLine();
}
private static string[,] LoadCSV(string filename)
{
// Get the file's text.
string whole_file = System.IO.File.ReadAllText(filename);
// Split into lines.
whole_file = whole_file.Replace('\n', '\r');
string[] lines = whole_file.Split(new char[] { '\r' },
StringSplitOptions.RemoveEmptyEntries);
// See how many rows and columns there are.
int num_rows = lines.Length;
int num_cols = lines[0].Split(',').Length;
// Allocate the data array.
string[,] values = new string[num_rows, num_cols];
// Load the array.
for (int r = 0; r < num_rows; r++)
{
string[] line_r = lines[r].Split(',');
for (int c = 0; c < num_cols; c++)
{
values[r, c] = line_r[c];
}
}
// Return the values.
return values;
}
}
}
the output i get :
ID;MenuName;ParentID;isHidden;LinkURL
1;Company;NULL;False;/company
2;About Us;1;False;/company/aboutus
3;Mission;1;False;/company/mission
4;Team;2;False;/company/aboutus/team
5;Client 2;10;False;/references/client2
6;Client 1;10;False;/references/client1
7;Client 4;10;True;/references/client4
8;Client 5;10;True;/references/client5
10;References;NULL;False;/references
and what should look like :
Example Output
. Company
.... About Us
....... Team
.... Mission
. References
.... Client 1
.... Client 2
See if following helps. I used your output as the input since I do not have the actual input. :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication176
{
class Program
{
const string FILENAME = #"c:\temp\test.csv";
static void Main(string[] args)
{
Menu menu = new Menu(FILENAME);
List<Menu> sortedRows = Menu.items.OrderBy(x => x).ToList();
menu.Print(sortedRows);
Console.ReadLine();
}
}
public class Menu : IComparable
{
public static List<Menu> items { get; set; }
public int ID { get; set; }
public string name { get; set; }
public int? parent { get; set; }
public Boolean hidden { get; set; }
public string[] linkUrl { get; set; }
public Menu() { }
public Menu(string filename)
{
StreamReader reader = new StreamReader(filename);
string line = "";
int rowCount = 0;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
if (++rowCount == 1)
{
items = new List<Menu>();
}
else
{
Menu newMenu = new Menu();
items.Add(newMenu);
string[] splitArray = line.Split(new char[] { ';' }).ToArray();
newMenu.ID = int.Parse(splitArray[0]);
newMenu.name = splitArray[1];
newMenu.parent = (splitArray[2] == "NULL")? null : (int?)int.Parse(splitArray[2]);
newMenu.hidden = Boolean.Parse(splitArray[3]);
newMenu.linkUrl = splitArray[4].Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
}
}
}
}
public int CompareTo(object obj)
{
Menu other = (Menu)obj;
int min = Math.Min(this.linkUrl.Length, other.linkUrl.Length);
for (int i = 0; i < min; i++)
{
int compare = this.linkUrl[i].CompareTo(other.linkUrl[i]);
if (compare != 0) return compare;
}
return this.linkUrl.Length.CompareTo(other.linkUrl.Length);
}
public void Print(List<Menu> rows)
{
foreach (Menu menu in rows)
{
if (!menu.hidden)
{
int length = menu.linkUrl.Length - 1;
Console.WriteLine(".{0} {1}", new string('.', 3 * length), menu.name);
}
}
}
}
}

Is it possible to get the item index using Contains?

When I use if (moscowCars.Contains(cars[x].Name)) it founds the value in a collection and I believe that not necessary to use moscowCars.RemoveAt(moscowCars.FindIndex(o => o.Equals(cars[x].Name))); to find it for a second time, just: moscowCars.Remove(cars[x].Name);. Of course, I can use try & catch instead of if, but I just want to know can I get the item index using Contains?
using System.Collections.Generic;
namespace Autoworld
{
class GoodCars
{
static List<Tech> cars = new List<Tech>();
public class Tech
{
public string Name { get; set; }
public double KM { get; set; }
}
static void Main()
{
List<string> moscowCars = new List<string>
{
"GAZ-330811 Aper", "Lada Vesta Sport"
};
cars.Add(new Tech() { Name = "Lada Vesta Sport", KM = 190 });
for (int x = 0; x < cars.Count; x++)
{
if (moscowCars.Contains(cars[x].Name))
{
moscowCars.RemoveAt(moscowCars.FindIndex(o => o.Equals(cars[x].Name)));
}
}
}
}
}
You could remove the two-step process entirely and just use .Remove which will return:
true if item is successfully removed; otherwise, false. This method
also returns false if itemwas not found in the List.
This would then look like:
for (int x = 0; x < cars.Count; x++)
{
moscowCars.Remove(cars[x].Name);
}
And if you need to handle the case where no car is found to be removed, you can wrap that call in an if condition like:
for (int x = 0; x < cars.Count; x++)
{
if (!moscowCars.Remove(cars[x].Name))
{
// Handle no cars to remove
}
}
Worth noting that behind the scenes, .Remove ultimately just gets the index and then removes the item at that index (which is what you were originally trying to do anyways):
public bool Remove(T item) {
int index = IndexOf(item);
if (index >= 0) {
RemoveAt(index);
return true;
}
return false;
}
See here for the source.
Alternatively, as others have stated, if you expect the List to contain more than item to be removed, you can use .RemoveAll:
moscowCars.RemoveAll(y => y == cars[x].Name);
And again, to handle the case where nothing is found:
if (moscowCars.RemoveAll(y => y == cars[x].Name) == 0)
{
// Handle no cars to remove
}
You can indeed use IndexOf(item)
this will give you the index of the item, or -1 if 'item' was not found (making this method double as a "contains" as well)
Use simply RemoveAt if you are sure you don't have any duplicated items anyway use the second way.
Solution
static List<Tech> cars = new List<Tech>();
public class Tech
{
public string Name { get; set; }
public double KM { get; set; }
}
static void Main()
{
List<string> moscowCars = new List<string>
{
"GAZ-330811 Aper", "Lada Vesta Sport"
};
cars.Add(new Tech() { Name = "Lada Vesta Sport", KM = 190 });
for (int x = 0; x < cars.Count; x++)
{
if (moscowCars.Contains(cars[x].Name))
{
moscowCars.RemoveAt(moscowCars.IndexOf(cars[x].Name));
}
}
}
Solution
static List<Tech> cars = new List<Tech>();
public class Tech
{
public string Name { get; set; }
public double KM { get; set; }
}
static void Main()
{
List<string> moscowCars = new List<string>
{
"GAZ-330811 Aper", "Lada Vesta Sport"
};
cars.Add(new Tech() { Name = "Lada Vesta Sport", KM = 190 });
for (int x = 0; x < cars.Count; x++)
{
if (moscowCars.Contains(cars[x].Name))
{
moscowCars.RemoveAll(o => o == cars[x].Name);
}
}
}
I hope it will help.

Iterate through ObservableCollection of class

I'm assigning values to a class by using ObservableCollection.Class contains MainItems and it's SubItems. Now how can I read all SubItems for each input of MainItem?
public class MainItems
{
public string ItemName { get; set; }
public ObservableCollection<SubItems> SubItemsList { get; set; }
}
public class SubItems
{
public string SubItemName { get; set; }
}
ObservableCollection<MainItems> _data = new ObservableCollection<MainItems>();
for (int i = 1; i <= 5; i++)
{
MainItems _mainItems = new MainItems();
_mainItems.ItemName = "Main" + i.ToString();
_mainItems.SubItemsList = new ObservableCollection<SubItems>();
for (int j = 1; j <= 3; j++)
{
SubItems _subItems = new SubItems()
{
SubItemName = "SubItem" + i.ToString()
};
_mainItems.SubItemsList.Add(_subItems);
}
_data.Add(_mainItems);
}
The foreach loop alway honors the collections(List, Array, Dictionary(special), ...) boundaries and iterates over all Elements, so its the shortest way to achieve what you want. It disallows you to add/remove elements from the currently iterated collection. In this case the classic for loop is your friend.
Full description from Microsoft:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in
Based on Fangs comment:
// foreach Version
foreach (MainItems mainItem in _data)
{
foreach (SubItems subItems in mainItem.SubItemsList)
{
Console.WriteLine($"{mainItem.ItemName} has a child {subItems.SubItemName}!");
}
}
// for Version
for (int i = 0; i < _data.Count; i++)
{
MainItems mainItem = _data[i];
for (int k = 0; k < mainItem.SubItemsList.Count; k++)
{
SubItems subItem = mainItem.SubItemsList[k];
Console.WriteLine($"{mainItem.ItemName} has a child {subItem.SubItemName}!");
}
}
// For Enumerator version
// get the input main item
string input = "Main1";
IEnumerable<ObservableCollection<SubItems>> ItemsforSelectedMainIem = _data.Where(x => x.ItemName == input).Select(x => x.SubItemsList);
var e = ItemsforSelectedMainIem.GetEnumerator();
while (e.MoveNext())
{
var v = e.Current.Select(x=>x.SubItemName).ToList();
foreach (var item in v)
{
Console.WriteLine(item);
}
}

How to change an object that was mocked?

In my Unit Test I need to change the value of the object that was mocked before. For example:
public class Cell
{
public int X { get; set; }
public int Y { get; set; }
public string Value { get; set; }
}
public class Table
{
private Cell[,] Cells { get; }
public Table(Cell[,] cells)
{
Cells = cells;
}
public void SetCell(int x, int y, string value)
{
Cells[x, y].Value = value;
}
}
I want to test SetCell method in Table.
So, first I mock Cell, then I create a Cell[,] array of cells, create a Table passing array of cells as a parameter.
SetCell doesn't work, because (I think) I can't change the object that was mocked before. How can I change it?
Here's my test:
ICell[,] cells = new ICell[3, 4];
for (int i = 0; i < cells.GetLength(0); i++)
{
for (int j = 0; j < cells.GetLength(1); j++)
{
var mock = new Mock<ICell>();
mock.Setup(m => m.X).Returns(i);
mock.Setup(m => m.Y).Returns(j);
mock.Setup(m => m.Value).Returns("");
cells[i, j] = mock.Object;
}
}
ITable table = new Table(cells);
table.SetCell(0, 0, "TEST"); // Cannot change it here :/
Setup all the properties so that they can be updated
ICell[,] cells = new ICell[3, 4];
for (int i = 0; i < cells.GetLength(0); i++)
{
for (int j = 0; j < cells.GetLength(1); j++)
{
var mock = new Mock<ICell>();
mock.SetupAllProperties();
mock.Object.X = i;
mock.Object.Y = j;
mock.Object.Value = "";
cells[i, j] = mock.Object;
}
}
//...other code removed for brevity

Create struct objects in a for loop

I have some troubls to create an struct object in for loop.
I have an UserData Struct:
public struct UserData
{
public string userID { get; set; }
public string userProjects { get; set; }
public string userAccess { get; set; }
//private List<UserData> list;
public UserData(string id,string project,string access):this()
{
this.userID = id;
this.userProjects = project;
this.userAccess = access;
// list = new List<UserData>();
}
}
So in another Class I try to make a List of my UserData Struct in a for loop:
Class ReadUserData
{
private List<UserData> userdata;
for (int j = 0; j < 4 ; j++)
{
userdata = new List<UserData>() { new
UserData(userID[j.ToString()],
userProject[j.ToString()],
useraccess[j.ToString()]) };
}
var firstuser = userdata.FirstOrDefault();
}
My Problem is that the count from the userData object is 1. It only create 1 object.
Where is my problem can you help?
Thanks
you must add objects to the list using Add method. currently you are overwriting list by putting new list into userdata
Class ReadUserData
{
private List<UserData> userdata = new List<UserData>();// create empty list
for (int j = 0; j < 4 ; j++)
{
userdata.Add(new
UserData(userID[j.ToString()],
userProject[j.ToString()],
useraccess[j.ToString()])); // add objects to the list at each iteration
}
var firstuser = userdata.FirstOrDefault();
}
More about List How to Add.
You are creating a new List<UserData> with ONE item and then you are assigning to userdata object. You are doing that repeatedly in every iteration, that's why.
Try this instead (create the list outside the loop, and Add one item at a time
Class ReadUserData
{
private List<UserData> userdata = new List<UserData>();
for (int j = 0; j < 4 ; j++)
{
userdata.Add( new
UserData(userID[j.ToString()],
userProject[j.ToString()],
useraccess[j.ToString()]) );
}
var firstuser = userdata.FirstOrDefault();
}

Categories

Resources