i have a datatable i created below i need to list all rows' cell length in datatable. my result must be not including "0" value. But my list : 19,19,19,19,19, 0.0.0.0..0.0..... so on why is it? How can i see length of my Array?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace DataTables
{
class Program
{
static void Main(string[] args)
{
DataTable table = GetTable();
int[] mySortedLists = new int[table.Rows.Count*table.Columns.Count];
foreach (DataColumn dc in table.Columns)
{
foreach (DataRow dr in table.Rows)
{
Console.WriteLine(dr[dc].ToString().Length);
}
Console.WriteLine("\t");
}
Console.WriteLine("--------------------------------------");
for (int i = 0; i < table.Rows.Count; i++)
{
for (int j = 0; j < table.Columns.Count; j++)
{
mySortedLists[i] += table.Rows[i][j].ToString().Length;
}
}
foreach (var mySortedList in mySortedLists)
{
Console.WriteLine(mySortedList.ToString() + "\n");
}
Console.ReadKey();
}
static DataTable GetTable()
{
//
// Here we create a DataTable with four columns.
//
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
//
// Here we add five DataRows.
//
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
return table;
}
}
}
Please help me!
You declare mySortedLists to have length table.Rows.Count * table.Columns.Count, but you only use the first table.Rows.Count entries. If you want one length value per row then you probably want:
int[] mySortedLists = new int[table.Rows.Count];
Or, if you want one length value per cell then you either want a two-dimensional array:
int[,] mySortedLists = new int[table.Rows.Count, table.Columns.Count];
...
mySortedLists[i, j] += table.Rows[i][j].ToString().Length;
Or you want to flatten the array indices:
mySortedLists[i * table.Columns.Count + j] += table.Rows[i][j].ToString().Length;
Unless I'm misunderstanding what you're trying to accomplish, your problem is in how you're declaring the mySortedLists array. You want it to declare it like this:
int[] mySortedLists = new int[table.Rows.Count];
To see the length of your array, you can use
Console.WriteLine(mySortedLists.Length);
I can't tell if you're trying to get the total length of the cells of each row, or the individual lengths of each cell in each row. Your array is declared with a length that would support the latter scenario, but you're only assigning values to it for the former scenario. Here are two Linq methods to get the length values stored, the first being putting the lengths into a jagged array that will have each field length.
int[][] lengths;
using (DataTable table = GetTable())
{
lengths = (from DataRow row in table.Rows
select
(from DataColumn col in table.Columns
select row[col].ToString().Length).ToArray()).ToArray();
}
foreach (int[] row in lengths)
{
Console.WriteLine(string.Join(",", row));
}
The second starts the same, but performs an aggregation at the end where the first .ToArray() was before, so it gets the total length of each individual row and stores it in an array.
int[] array;
using (DataTable table = GetTable())
{
array = (from DataRow row in table.Rows
select
(from DataColumn col in table.Columns
select row[col].ToString().Length).Sum()).ToArray();
}
foreach (int value in array)
Console.WriteLine(value);
Related
I have a DataTable like this:
And I want to write a for loop that shows debit and credit line on its own separate line like this:
Here is my unfinished code:
DataTable dt = new DataTable();
dt.Columns.Add("DEBIT", typeof(string));
dt.Columns.Add("CREDIT", typeof(string));
dt.Columns.Add("AMOUNT", typeof(double));
dt.Rows.Add("Debit1", "Credit1", 10);
dt.Rows.Add("Debit2", "Credit2", 8);
dt.Rows.Add("Debit3", "Credit3", 12);
for (int i=1; i <= dt.Rows.Count; i++)
{
//The first image (datatable) has three debit and credit lines are showing on the same line. Normally the debit line and credit line are showing on its own separate lines.
//With above given datatable I want to construct for loop that shows three debit lines and three credit lines as demonstrated in the second image. In this case it shows 6 lines
}
I would much appreciate it if you could help me with this.
Steps:
Start the loop in reverse (so you can easily insert rows).
Create a new row for the credit and fill it with the relevant data.
Remove the credit data from the original row.
Insert the new column in the position following the original row.
Something like this should do the trick:
for (int i = dt.Rows.Count - 1; i >= 0; i--)
{
var row = dt.Rows[i];
if (!string.IsNullOrEmpty(row["CREDIT"].ToString()))
{
var creditRow = dt.NewRow();
creditRow["CREDIT"] = row["CREDIT"];
creditRow["AMOUNT"] = row["AMOUNT"];
row["CREDIT"] = string.Empty;
dt.Rows.InsertAt(creditRow, i + 1);
}
}
Try it online.
I'm building a two-dimensional array of data. I'd like to set the first row of this array to the contents of a one-dimensional array with the proper number of columns, like this:
private string[] GetHeaders() {
return new string[] { "First Name", "Last Name", "Phone" };
}
private void BuildDataArray(IEnumerable<Person> rows) {
var data = new string[rows.Count() + 1, 3];
// This statement is invalid, but it's roughly what I want to do:
data[0] = GetHeaders();
var i = 1;
foreach (var row in rows) {
data[i, 0] = row.First;
data[i, 1] = row.Last;
data[i, 2] = row.Phone;
i++;
}
}
Basically, I'd like a simpler way to fill the first row rather than needing to iterate over each item like I do with the rows elements.
Is there a C# idiom for doing this?
You should change your syntax:
var data = new string[rows.Count()][];
// This should be valid, an array of arrays
data[0] = GetHeaders();
var i = 1;
foreach (var row in rows) {
data[i][0] = row.First;
data[i][1] = row.Last;
data[i][2] = row.Phone;
i++;
}
I've got two arrays, and I need to put the second forward items to the other array using Array.Copy, but nothing happens, it just does not add anything.
Here's the code:
DataRow[] auxRows = rFComDataSet.TestStepNames
.Select("ScenarioName = '" + scenarioName + "'");
DataRow[] newRows = new DataRow[auxRows.Count()];
auxRows.CopyTo(newRows, 0);
foreach (DataRow row in newRows)
{
DataRow teste = this.rFComDataSet.TestStepNames.NewRow();
Array.Copy(row.ItemArray, 1, teste.ItemArray, 0, 4);
row["ScenarioName"] = newScenarioName;
this.rFComDataSet.TestStepNames.Rows.Add(row.ItemArray);
}
This behavior is the consequence of the implementation of the ItemArray property.
This is the code of the GET accessor
public object[] ItemArray
{
get
{
int num;
object[] objArray;
DataColumn column;
int num2;
num2 = this.GetDefaultRecord();
objArray = new object[this._columns.Count];
num = 0;
goto Label_0037;
Label_001C:
column = this._columns[num];
objArray[num] = column[num2];
num += 1;
Label_0037:
if (num < ((int) objArray.Length))
{
goto Label_001C;
}
return objArray;
}
}
As you can see calling DataRow.ItemArray returns a new object array where the values from the underlyng row are copied to.
When you use Array.Copy you are setting values in this array not in
the underlying values of the DataRow. So your row remains with the null values
A possible workaround is the following (NOT TESTED)
object[] itemArray = new object[this.rFComDataSet.TestStepNames.Columns.Count];
Array.Copy(row.ItemArray, 1, itemArray, 0, 4);
this.rFComDataSet.TestStepNames.Rows.Add(itemArray);
In this way we force the underlying values of new row created by Rows.Add to be the value of the object array created separately
There are a couple of things to take note however. Your call auxRows.CopyTo(newRows, 0); doesn't create a new row, it just copy all the rows reference to the new array, but they points at the same data, so changing anything in newRows change the corresponding row in auxRows.
Finally it is not clear why you have all this work to copy the row and then add to the TestStepNames table the same row from the foreach loop
Just skip Copy and do like:
DataRow teste = this.rFComDataSet.TestStepNames.NewRow();
teste.ItemArray = row.ItemArray;
row.ItemArray will create a new object for you.
What's the fastest way in term of speed of coding to add rows to a DataTable? I don't need to know neither the name of columns nor datatype. Is it possible to add rows without previously specify the number or name of dataTable columns?
DataTable t = new DataTable();
t.Rows.Add(value1,
value1,
value2,
value3,
...
valueN
);
DataSet ds = new DataSet();
ds.Tables.Add(t);
If the input comes out of a collection, you could loop it to create the DataColumns with the correct type:
var data = new Object[] { "A", 1, 'B', 2.3 };
DataTable t = new DataTable();
// create all DataColumns
for (int i = 0; i < data.Length; i++)
{
t.Columns.Add(new DataColumn("Column " + i, data[i].GetType()));
}
// add the row to the table
t.Rows.Add(data);
To answer your first question: no, you have to have columns defined on the table. You can't just say, "Hey, make a column for all these values." Nothing stopping you from creating columns on the fly, though, as Mr. Schmelter says.
Without knowing the rows or columns (you first need to add columns, without that not possible)
for(int intCount = 0;intCount < dt.Rows.Count; intCount++)
{
for(int intSubCount = 0; intSubCount < dt.Columns.Count; intSubCount++)
{
dt.Rows[intCount][intSubCount] = yourValue; // or assign to something
}
}
How can I merge DataTable objects ignoring the first row?
The datatable I need to merge with the one I've got comes from a parsed CSV file and its first row (sometimes) still contains headers, which are obviously not supposed to end up in the resulting table...
DataTable.Merge method does not seem to offer such an option. What's the best way to do that? Just removing the first row beforehand? But that affects (alters) the "original", and what if I wanted it to stay as it was. Removing and reinserting after the merge? Smells like "clever coding". Is there really no better way?
Editing my previous
I wrote code on similar lines and ended up with all rows of dt1 intact and dt2 containing only row 2 &3 of from dt1
var dt1 = new DataTable("Test");
dt1.Columns.Add("id", typeof(int));
dt1.Columns.Add("name", typeof(string));
var dt2 = new DataTable("Test");
dt2.Columns.Add("id", typeof(int));
dt2.Columns.Add("name", typeof(string));
dt1.Rows.Add(1, "Apple"); dt1.Rows.Add(2, "Oranges");
dt1.Rows.Add(3, "Grapes");
dt1.AcceptChanges();
dt1.Rows[0].Delete();
dt2.Merge(dt1);
dt2.AcceptChanges();
dt1.RejectChanges();
Let me know if you find it acceptable.
Vijay
You could go through the rows separately and merge them into the table, something like
public static class DataTableExtensions
{
public static void MergeRange(this DataTable dest, DataTable table, int startIndex, int length)
{
List<string> matchingColumns = new List<string>();
for (int i = 0; i < table.Columns.Count; i++)
{
// Only copy columns with the same name and type
string columnName = table.Columns[i].ColumnName;
if (dest.Columns.Contains(columnName))
{
if (dest.Columns[columnName].DataType == table.Columns[columnName].DataType)
{
matchingColumns.Add(columnName);
}
}
}
for (int i = 0; i < length; i++)
{
int row = i + startIndex;
DataRow destRow = dest.NewRow();
foreach (string column in matchingColumns)
{
destRow[column] = table.Rows[row][column];
}
dest.Rows.Add(destRow);
}
}
}