Initiate jagged list - c#

I am trying to make a jagged list. It gets filled with values depending on two variable int's: rows, and cols.
The pattern is to have the list filled like this when rows = 4 and cols = 3:
00,
10,
20,
01,
11,
21,
02,
12,
22,
03,
13,
23
Each double digit is a sub-list containing column, and then row.
This is what i have:
namespace WindowsFormsApplication11
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
defineCellPositionsList();
displayCellPositionsList();
}
int rows = 4;
int cols = 3;
private List<List<int>> CellPositionsList = new List<List<int>>();
private void defineCellPositionsList()
{
for (int i = 0; i < (rows * cols); i++)
{
List<int> sublist = new List<int>();
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
sublist.Add(col);
sublist.Add(row);
}
}
CellPositionsList.Add(sublist);
}
}
private void displayCellPositionsList()
{
for (int i = 0; i < CellPositionsList.Count; i++)
{
label1.Text += CellPositionsList[i][0];
label1.Text += CellPositionsList[i][1] + "\n";
}
}
}
}
The jagged list should have 12 sub-lists. The sub-lists should have 2 values. This is working. However each value is 0. Clearly i am slightly off with my logic. Any help appreciated. Thanks.

The problem is not that each of your sublists is { 0, 0 }, but rather that each one is a sublist of the full 24 items, which happens to begin with the numbers 0, 0. You can verify this by checking CellPositionsList[i].Count.
The bug is due to too much looping when the lists are created. You don't need three loops, two are correct:
private void defineCellPositionsList()
{
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
{
CellPositionsList.Add(new List<int> { col, row });
}
}
}
And there is also no need to write all of this longhand, as LINQ provides an IMHO better alternative:
CellPositionsList = Enumerable.Range(0, rows)
.SelectMany(r => Enumerable.Range(0, cols).Select(c => new List<int> {c,r}))
.ToList();

defineCellPositionsList() seems to be using the same sublist for every iteration. The first two elements in sublist are 0, 0, but there are a total of 24 eventually added.
To fix this, move the declaration of sublist inside the first loop.
I do see plenty of non-zero values in the sublists. It may be worth noting that you appear to be putting all the values into a single label in displayCellPositionsList.
I was totally wrong about that stuff.
But this stuff is right. I've executed and it works. (assuming I understand what you're trying to do, it's still a little vague)
If you have a list of rows, and a list of columns, and then finally a 2-list of coordinates, then you really have 3 sets of nested lists. I'm not sure exactly what you're doing or why you want it that way, but if that's what you really want, then your CellPositionsList really needs to be List<List<List<int>>>. If you do that, you can use this code:
for (int row = 0; row < rows; row++) {
CellPositionsList.Add(new List<List<int>>());
for (int col = 0; col < cols; col++) {
CellPositionsList[row].Add(new List<int> {row, col});
}
}

Related

How to create a 3D List in C#

I have a list which is made up of 2 lists with the following numbers:
list(1) = (2,3,5,3)
list(2) = (1,3,9,2).
Now I have to create two matrix:
The first matrix 4x4 should have all the elements of list(1) on the diagonal, the rest of the numbers should be zero.
The second matrix 4x4 should have all the elements of list(2) on the diagonal. The rest of the numbers should be zero.
I want to do this with a for loop.
Could you please help me? I don't know how to start, I'm new in C# and I can't find references in which it's clear how to work with 3D matrix as I did with Matlab.
Thanks a lot!
Create a regular List<int> for the first list.
List<int> list = new List<int>() { 2, 3, 5, 3 };
Then your 'matrix'(which really is a 2D array):
int[,] matrix = new int[4, 4];
Now, the diagonal means column == row, so using two loops you can enter the value only when that condition is met.
for (int row = 0; row < list.Count; row++)
{
for (int col = 0; col < list.Count; col++)
{
if (col == row)
matrix[row, col] = list[row];
else
matrix[row, col] = 0;
}
}
Confirmation:
And do the same thing for the 2nd list. You could easily write a function that would do this.
EDIT
Here it is put into a function, and how to use it.
static int[,] CreateMatrix(List<int> list)
{
int[,] matrix = new int[list.Count, list.Count];
for (int row = 0; row < list.Count; row++)
{
for (int col = 0; col < list.Count; col++)
{
if (col == row)
matrix[row, col] = list[row];
else
matrix[row, col] = 0;
}
}
return matrix;
}
Calling:
var list1 = new List<int>() { 2, 3, 5, 3 };
var list2 = new List<int>() { 1, 3, 9, 2 };
var matrix1 = CreateMatrix(list1);
var matrix2 = CreateMatrix(list2);

remove list item based on index c#

I have two lists.
First list contains values such as letters and numbers.
Length is [0]-[36].
Second list contains similar values and length is also [0]-[36].
I iterate second list twice with specific values to grab an Index key and when I grab Index key from second list, I want to remove items in first list based on Indexes from second one.
Problem is that second iteration doesn't work anymore, because index key has changed in first list.
I should probably convert list to an array (array has fixed index keys, list generates after) but I don't know how to add or remove index key from an array.
I don't use Linq.
Appreciate your help and suggestions
BR
Code sample:
List<int> list_z = new List<int>();
List<int> list_k = new List<int>();
for (int i = 0; i < second_list.Count; i++) {
if (second_list[i] == "K")
{
list_k.Add(i);
}
}
int k = list_k.Count;
for (int i = 0; i < k; i++) {
first_list.RemoveAt(list_k[i]);
}
for (int i = 0; i < second_list.Count; i++)
{
if (second_list[i] == "Z")
{
list_z.Add(i);
}
}
int z = list_z.Count;
for (int i = 0; i < svi_z; i++)
first_list.RemoveAt(lista_z[i]); //here is error, because first_list doesnt have index key number 36 anymore
}
When removing items from a list based on indexes, you should remove them in descending order (e.g. you should remove 11th, 8th, 3d, 2nd items - in this order). In your case:
list_k.Sort();
for (int i = list_k.Count - 1; i >= 0; --i)
first_list.RemoveAt(list_k[i]);
There is a simple solution for removing items from list at a specific index one after the other. That is to order the indexes descending, this way you'll not have any items moved around in the list.
Example:
The Below throws an error:
List<int> list = Enumerable.Range(0, 20).ToList();
List<int> indexesToRemove = new List<int>(){ 5, 13, 18 };
foreach(int i in indexesToRemove)
{
list.RemoveAt(i);
}
While if you do this, you'll get no error:
List<int> list = Enumerable.Range(0, 20).ToList();
List<int> indexesToRemove = new List<int>(){ 5, 13, 18 };
foreach(int i in indexesToRemove.OrderByDescending(x => x))
{
list.RemoveAt(i);
}
So in your case, you just need to call list_z = list_z.OrderByDescending(x => x).ToList(); before the loop and everything should work fine.
Or if you don't want to use linq you can do the following:
list_z.Sort((x, y) => y - x);
for (int i = 0; i < list_z.Count; i++)
first_list.RemoveAt(lista_z[i]);
}
Or you can simplify what your doing:
// Iterate and assign null
for (var i = 0; i < second_list.Count(); i++)
{
if (second_list[i] == "K")
{
first_list[i] = null;
}
}
// Iterate and assign null
for (var i = 0; i < second_list.Count; i++)
{
if (second_list[i] == "Z")
{
first_list[i] = null;
}
}
// remove nulls without linq or lambda
first_list.RemoveAll(delegate (string o) { return o == null; });

How do I use For Loop twice to find datatable columns and rows?

I want to use for loop to get average of datatable columns and rows. What I want to do is that what if there are 100 ~ 1000 columns and rows, I can't keep on adding them in the code. is there one simple code that can get average of automatically as I add columns and rows?
here is my code, I am stuck I don't know what to write in ?? area below and this code gets me error please help...
private void button1_Click(object sender, EventArgs e)
{
DataTable dtGrid = gridData.DataSource as DataTable;
DataTable dtResult = new DataTable();
Math columnIndex = new Math();
List<double> avgList = new List<double>();
for (int i = 0; i < dtGrid.Columns.Count; i++)
{
for (int k = 1; k < dtGrid.Rows.Count; k++)
{
// ??
avgList.Add(Convert.ToDouble(dtGrid.Rows[i].ToString()));
}
}
//this is from other class name Math
/* public double getAverageValue(List<double> avgList)
{
double averageList = 0;
averageList = MathNet.Numerics.Statistics.Statistics.Mean(avgList.ToList());
return averageList;
}*/
double averageX1 = columnIndex.getAverageValue(avgList);
List<Math> list = new List<Math>();
//using get; set from other class
list.Add(new Math { Result = "Average", X1 = averageX1.ToString() });
gridData2.DataSource = list;
}
}
}
It looks like your loop is inside out. Try this:
DataTable dtGrid = gridData.DataSource as DataTable;
DataTable dtResult = new DataTable();
Math columnIndex = new Math();
List<double> avgList = new List<double>();
for (int k = 1; k < dtGrid.Rows.Count; k++)
{
for (int i = 0; i < dtGrid.Columns.Count; i++)
{
// ??
avgList.Add(Convert.ToDouble(dtGrid.Rows[k].Columns[i].ToString()));
}
}
This logic averages all columns in a row together. If you need,, you can create a Dictionary and average each column separately. Something like thisL
Dictionary<int, List<double>> AvgColumnList = new Dictionary<int, System.Collections.Generic.List<double>>();
This uses a dictionary that contains a list for each column in the row. If there are 100 columns, then there will be 100 entries in the dictionary with index 0 - 99. Each dictionary item will contain a list of doubles.
for (int k = 1; k < dtGrid.Rows.Count; k++)
{
for (int i = 0; i < dtGrid.Columns.Count; i++)
{
if (!AvgColumnList.Keys.Contains(i))
AvgColumnList.Add(i, new List<double>());
AvgColumnList[i].Add(Convert.ToDouble(dtGrid.Rows[k].Columns[i].ToString()));
}
}
DataTable is zero index based, in your code row count started from 1 it should be 0, also dtGrid.Rows[i] is a row not the cell value. Use below code to loop through each cell of a DataTable
Update : Code updated as OP want to save each column data separately and irrespective of column numbers.
List<List<double>> perColumnAvg = new List<List<double>>();
for (int i = 0; i < dtGrid.Columns.Count; i++)
{
avgList = new List<double>();
for (int k = 0; k < dtGrid.Rows.Count; k++)
{
// ??
avgList.Add(Convert.ToDouble(dtGrid.Rows[k][i].ToString()));
}
perColumnAvg.Add(avgList);
}
Now you can compute individual column average as
foreach (var columnList in perColumnAvg)
{
// place your logic here.
columnIndex.getAverageValue(columnList);
}
And can compute avg across table using.
double tableAvg = columnIndex.getAverageValue(perColumnAvg.SelectMany(s=>s));

C# - Creating 2 dimensional array from multiple datagridviews

I am relatively new to c# and am having a problem filling a 2 dimensional array.
public string[,] myGridData = new string[50, 5];
The array data is contained in 7 datagridviews, each with 7rows x 5 columns.
I know how to get the data from the first grid, but am not sure how to loop through all 7 grids.
//Populate Array with data from grid 1 (7 rows,5 columns)
for (int rows = 0; rows < dgv1.Rows.Count; rows++)
{
for (int col = 0; col < dgv1.Rows[rows].Cells.Count; col++)
{
myGridData[rows, col] = dgv1.Rows[rows].Cells[col].Value.ToString();
}
}
Any help would be appreciated.
Thank You
Since you have said you have 7 data grid views and that each has dimensions 7 x 5 I have removed some of the loop constraints and replaced them with constants. I wouldn't normally recommend that, but since you are using 2 dimensional arrays and you've specified the values it is the simplest way to go.
Here's the code:
var dgvs = new [] { dgv1, dgv2, dgv3, dgv4, dgv5, dgv6, dgv7, };
for (var i = 0; i < dgvs.Length; i++)
{
for (int rows = 0; rows < 7; rows++)
{
for (int col = 0; col < 5; col++)
{
myGridData[rows + i * 7, col] = dgv1[i].Rows[rows].Cells[col].Value.ToString();
}
}
}

Simplest way of programmatically creating a DataGridView with X columns by Y rows

In C# Winforms, I'd like to use a DataGridView as a simple widget to store information to display to the user. To this end, I'd like to create a table of say, 5x10 cells.
After some research, solutions tend to allow adding just one row or column at a time. I'd like the whole grid created initially and straight away, so I can start populating it with data, like you would with a standard C# 2D array.
What's the simplest way of going about this? A function header could look like this:
createCells(DataGridView dgv, int cols, int rows) {}
It should be quick and amenable to changing the cols and rows to a larger or smaller number later on if need be.
By the way, there might an error like:
Sum Of The Columns' FillWeight Values Cannot Exceed 65535
To avoid it, set AutoGenerateColumns property to false, and set FillWeight to 1 for each column generated:
dgv.AutoGenerateColumns = false;
for (int i = 1; i <= columns; i++)
{
dgv.Columns.Add("col" + i, "column " + i);
dgv.Columns[i - 1].FillWeight = 1;
}
for (int j = 0; j < rows; j++)
dgv.Rows.Add();
You can do by using for loops in this way:
private DataGridView DGV_Creation(DataGridView dgv, int columns, int rows)
{
for (int i = 1; i <= columns; i++)
{
dgv.Columns.Add("col" + i, "column " + i);
}
for (int j = 0; j < rows; j++)
{
dgv.Rows.Add();
}
return dgv;
}
Call it with:
this.dataGridView1 = DGV_Creation(dataGridView1, 5, 10); // 5 columns, 10 rows (empty rows)
or:
private void DGV_Creation(ref DataGridView dgv, int columns, int rows)
{
for (int i = 1; i <= columns; i++)
dgv.Columns.Add("col" + i, "column " + i);
for (int j = 0; j < rows; j++)
dgv.Rows.Add();
}
call it with:
DGV_Creation(ref this.dataGridView1, 5, 10); //5 columns, 10 rows (empty rows)

Categories

Resources