Sorting a DataTable by columns in a file - c#

I am reading a csv file and sorting it.
I am trying to sort a DataTable to give me a output based on Bankname from datatable
here is the code I already have:
DataTable dt = new DataTable();
dt.Columns.Add("accountholder", typeof(string));
dt.Columns.Add("accountnumber", typeof(int));
dt.Columns.Add("accounttype", typeof(string));
dt.Columns.Add("bankname", typeof(string));
dt.Columns.Add("branch", typeof(string));
dt.Columns.Add("amount", typeof(double));
dt.Columns.Add("date", typeof(DateTime));
string line;
//CultureInfo culture = CultureInfo.InvariantCulture;
StreamReader sr = new StreamReader(#"C:\\Test\\debitorders.csv");
StreamWriter sw = new StreamWriter(#"C:\\Test\\output.txt");
while ((line = sr.ReadLine()) != null)
{
if (line.Length > 0)
{
string[] inputArray = line.Split(new char[] { ',' });
dt.Rows.Add(new object[] {
inputArray[0].Trim().Substring(0,1),
inputArray[1].Trim(),
long.Parse(inputArray[2].Trim()),
inputArray[3].Trim(),
inputArray[4].Trim(),
inputArray[5].Trim(),
(long)(100 * double.Parse(inputArray[6].Trim())),
DateTime.Parse(inputArray[7].Trim())
});
DateTime date = account.Field<DateTime>("date");
string[] outputLine = new string[]{
initial,
accountholder,
accountnumber.ToString(),
accounttype,
bankname,
branch,
amount.ToString(),
date.ToShortDateString()
};
Console.WriteLine(string.Join(",",outputLine));
}
}
Console.ReadLine();
Any help will be appreciated.
Thank you

Your code and posted desired result doesn't seem to be consistent so you probably have to adapt my code to your needs. But my code example will show you how to get rid of the DataTable and DataRow stuff. Instead LINQ methods are used where possible and a simple helper method for reading the csv file. If you have any further questions about the code let me know.
//reading the csv and create anonymous object for each line
var inputEntries = File.ReadLines(#"C:\\Test\\debitorders.csv")
.Select(line =>
{
var values = line.Split(',');
return new
{
AccountHolder = values[0].Trim().Substring(0,1) + values[1].Trim(),
AccountNumber = long.Parse(values[2].Trim()),
AccountType = values[3].Trim(),
BankName = values[4].Trim(),
Branch = values[5].Trim(),
Amount = 100 * double.Parse(values[6].Trim()),
Date = DateTime.Parse(values[7].Trim())
};
});
var banks = inputEntries
.OrderBy(e => e.BankName)
.GroupBy(e => e.BankName, e => e);
//output data
foreach(var bank in banks)
{
//output bank header
var AccountName = bank.Key;
if (AccountName.Length >= 16)
{
AccountName = AccountName.Substring(0, 16);
}
else
{
AccountName += new string(' ', 16 - AccountName.Length);
}
var NumberOfAccounts = bank.Count();
var TotalAmount = bank.Select(acc => acc.Amount).Sum();
var Header = NumberOfAccounts.ToString("000") + TotalAmount.ToString("0000000000");
Console.WriteLine(Header);
//sort accounts
var sortedAccounts = bank
.OrderBy( acc=> acc.AccountHolder)
.OrderByDescending(acc => acc.Amount);
//output accounts
foreach( var account in sortedAccounts)
{
var outputLine =
account.AccountHolder +
account.AccountNumber +
account.AccountType +
account.Amount +
account.Date.ToShortDateString();
Console.WriteLine(outputLine);
}
}

Related

add two group into one group in c#

I have two groups like below, theyh have different data. Based on both I need to create an xml file .
How can I write a for-loop for both groups and generate a single xml file?
var groups = checkFile.AsEnumerable().GroupBy(x => new { DocNum = x.Field<int>("orderid"), Type = x.Field<string>("Type"), ProdName = x.Field<string>("ProdName"), Status = x.Field<string>("Status"), productno = x.Field<string>("productno"), uom = x.Field<string>("uom"), customer = x.Field<string>("customer"), remark = x.Field<string>("remark"), U_JobNumber = x.Field<string>("U_JobNumber"), U_SalesPerson = x.Field<string>("U_SalesPerson"), U_POnum = x.Field<string>("U_POnum"), U_JobType = x.Field<string>("U_JobType"), PlannedQty = x.Field<decimal>("PlannedQty"), OriginNum = x.Field<int?>("OriginNum"), orderdate = x.Field<DateTime>("orderdate"), duedate = x.Field<DateTime>("duedate"), DocTotal = x.Field<decimal>("DocTotal") });
var groups2 = checkFile2.AsEnumerable().GroupBy(x => new { DocNum = x.Field<int>("DocNum") });
//now i need to take both group data inside this loop to print the file
foreach (var group in groups)
{
var stringwriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringwriter, new XmlWriterSettings { Indent = true }))
{
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("Root");
xmlWriter.WriteEndElement();
}
var xml = stringwriter.ToString();
XmlDocument docSave = new XmlDocument();
docSave.LoadXml(stringwriter.ToString());
docSave.Save(System.IO.Path.Combine(#SystemSettings.ImportBankStatementPendingFolderPath, "DocNum -" + group.Key.DocNum + ".xml"));
count++;
}
Try following :
DataTable checkFile = new DataTable();
var groups = checkFile.AsEnumerable().GroupBy(x => new
{
DocNum = x.Field<int>("orderid"),
Type = x.Field<string>("Type"),
ProdName = x.Field<string>("ProdName"),
Status = x.Field<string>("Status"),
productno = x.Field<string>("productno"),
uom = x.Field<string>("uom"),
customer = x.Field<string>("customer"),
remark = x.Field<string>("remark"),
U_JobNumber = x.Field<string>("U_JobNumber"),
U_SalesPerson = x.Field<string>("U_SalesPerson"),
U_POnum = x.Field<string>("U_POnum"),
U_JobType = x.Field<string>("U_JobType"),
PlannedQty = x.Field<decimal>("PlannedQty"),
OriginNum = x.Field<int?>("OriginNum"),
orderdate = x.Field<DateTime>("orderdate"),
duedate = x.Field<DateTime>("duedate"),
DocTotal = x.Field<decimal>("DocTotal")
});
DataTable checkFile2 = new DataTable();
//now i need to take both group data inside this loop to print the file
foreach (var group in groups)
{
List<DataRow> groups2 = checkFile2.AsEnumerable().Where(x => group.Key.DocNum == x.Field<int>("DocNum")).ToList();
}

How to convert string separated by new line and comma to DataTable in C#

I have a string like this:
"Product,Price,Condition
Cd,13,New
Book,9,Used
"
Which is being passed like this:
"Product,Price,Condition\r\Cd,13,New\r\nBook,9,Used"
How could I convert it to DataTable?
Trying to do it with this helper function:
DataTable dataTable = new DataTable();
bool columnsAdded = false;
foreach (string row in data.Split(new string[] { "\r\n" }, StringSplitOptions.None))
{
DataRow dataRow = dataTable.NewRow();
foreach (string cell in row.Split(','))
{
string[] keyValue = cell.Split('~');
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(keyValue[0]);
dataTable.Columns.Add(dataColumn);
}
dataRow[keyValue[0]] = keyValue[1];
}
columnsAdded = true;
dataTable.Rows.Add(dataRow);
}
return dataTable;
However I don't get that "connecting cells with appropriate columns" part - my cells don't have ~ in string[] keyValue = cell.Split('~'); and I obviously get an IndexOutOfRange at DataColumn dataColumn = new DataColumn(keyValue[0]);
Based on your implementation, I have written the code for you, I have not tested it. But you can use the concept.
DataRow dataRow = dataTable.NewRow();
int i = 0;
foreach (string cell in row.Split(','))
{
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(cell);
dataTable.Columns.Add(dataColumn);
}
else
{
dataRow[i] = cell;
}
i++;
}
if(columnsAdded)
{
dataTable.Rows.Add(dataRow);
}
columnsAdded = true;
You can do that simply with Linq (and actually there is LinqToCSV on Nuget, maybe you would prefer that):
void Main()
{
string data = #"Product,Price,Condition
Cd,13,New
Book,9,Used
";
var table = ToTable(data);
Form f = new Form();
var dgv = new DataGridView { Dock = DockStyle.Fill, DataSource = table };
f.Controls.Add(dgv);
f.Show();
}
private DataTable ToTable(string CSV)
{
DataTable dataTable = new DataTable();
var lines = CSV.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var colname in lines[0].Split(','))
{
dataTable.Columns.Add(new DataColumn(colname));
}
foreach (var row in lines.Where((r, i) => i > 0))
{
dataTable.Rows.Add(row.Split(','));
}
return dataTable;
}
You can split given string into flattened string array in one call. Then you can iterate through the array and populate list of objects.
That part is optional, since you can immediately populate DataTable but I think it's way easier (more maintainable) to work with strongly-typed objects when dealing with DataTable.
string input = "Product,Price,Condition\r\nCd,13,New\r\nBook,9,Used";
string[] deconstructedInput = input.Split(new string[] { "\r\n", "," }, StringSplitOptions.None);
List<Product> products = new List<Product>();
for (int i = 3; i < deconstructedInput.Length; i += 3)
{
products.Add(new Product
{
Name = deconstructedInput[i],
Price = Decimal.Parse(deconstructedInput[i + 1]),
Condition = deconstructedInput[i + 2]
});
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Condition { get; set; }
}
So, products collection holds 2 objects which you can easily iterate over and populate your DataTable.
Note: This requires further checks to avoid possible runtime exceptions, also it is not dynamic. That means, if you have differently structured input it won't work.
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn(nameof(Product.Name)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Price)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Condition)));
foreach (var product in products)
{
var row = dataTable.NewRow();
row[nameof(Product.Name)] = product.Name;
row[nameof(Product.Price)] = product.Price;
row[nameof(Product.Condition)] = product.Condition;
dataTable.Rows.Add(row);
}

How to convert table format to string programmatically

Good day all,
would like request to how to convert table format to string
eg:
Material Control August
Development September
Planning August
HR September
to
September: Development, HR
August : Material Control, Planning
List<String> returnvalueStringMonth = new List<String>();
List<String> returnvalueStringDept = new List<String>();
foreach (DataRow dr in dsSeries.Tables[0].Rows)
{
string newmanout = dr["MonthNames"].ToString();
returnvalueStringMonth.Add(newmanout);
string Departs = dr["Depart"].ToString();
returnvalueStringMonth.Add(Departs);
//var DDLName = dr["Depart"];
//Label dynamicLabel = new Label();
//dynamicLabel.Text = DDLName.ToString() + ",";
//div1.Controls.Add(dynamicLabel);
//var sumPlus = Convert.ToDouble(newmanout) +",";
}
List<string> b = new List<string>();
b.AddRange(returnvalueStringMonth.Distinct());
for (int cs = 0; cs < b.Count; cs++)
{
//Panel aspPanel = new Panel();
Label dynamicLabel = new Label();
dynamicLabel.Text = b[cs].ToString()+":" + "<br/>";
div1.Controls.Add(dynamicLabel);
}
I able achive until month only, then i realize made mistake.
So, please advise how to achive this.
The code below will fill a list of strings with your desired output. You can change the second loop to do what you want.
var monthList = new Dictionary<String, List<String>>();
foreach (DataRow dr in dsSeries.Tables[0].Rows)
{
var key = dr["MonthName"].ToString();
var value = dr["Department"].ToString();
if (!monthList.ContainsKey(key))
{
monthList.Add(key, new List<string>());
}
monthList[key].Add(value);
}
List<string> b = new List<String>();
foreach (var month in monthList.Keys)
{
b.Add(month + ": " + String.Join(", ", monthList[month])");
}
If you would rather use LINQ, you can do this instead:
var q = from row in dsSeries.Tables[0].AsEnumerable()
group row by row["Month"] into qGrouped
orderby qGrouped.Key
select String.Format("{0}: {1}", qGrouped.Key,
String.Join(", ", Array.ConvertAll(qGrouped.ToArray(), r => r["Department"])));
var b = q.ToList();
public class TestClass
{
public string S1 { get; set; }
public string S2 { get; set; }
}
[TestMethod]
public void MyTest()
{
// Material Control August
//Development September
//Planning August
//HR September
var list = new List<TestClass>
{
new TestClass {S1 = "Material Control", S2 = "August"},
new TestClass {S1 = "Development", S2 = "September"},
new TestClass {S1 = "Planning", S2 = "August"},
new TestClass {S1 = "HR", S2 = "September"}
};
var listGroupByMonth = list.GroupBy(l => l.S2);
foreach (var lstByMonth in listGroupByMonth)
{
var key = lstByMonth.Key;
var finalValue = string.Join(", ", lstByMonth.ToList().Select(lbm => lbm.S1));
}
}

CSV Parse out object c#

I need some help with parsing out a CSV we get it like this
OrderNumber,LineNumber,CustomerNumber,CustomerName,AddressLine1,AddressLine2,AddressLine3,AddressLine4,AddressLine5,PostCode,ProductCode,ProductName,Ordered,Left,Picked
we can have multiple lines for an order so we would get
order Number
CustomerNumber
CustomerName
AddressLine1
AddressLine2
AddressLine3
AddressLine4
AddressLine5
PostCode
matching multiple times I need a way of parsing this out to be this structure
<orderDespatchRequest>
<despatchDetails>
<clientCustomerId>CustomerNumber</clientCustomerId>
<clientOrderNumber>OrderNumber</clientOrderNumber>
<dateDespatch>2015-07-01T00:00:00</dateDespatch>
<despatchedDetail>
<orderDespatchDetail>
<lineNumber>LineNumber</lineNumber>
<productCode>ProductCode</productCode>
<productName>ProductName</productName>
<quantity>Picked</quantity>
</orderDespatchDetail>
</despatchedDetail>
</despatchDetails>
</orderDespatchRequest>
Hope someone can Help?
This is what I have got so far
public bool ExtractCSV(string file)
{
#region set up new dataTable
dt = new DataTable("Header");
dt.Columns.Add("OrderNumber", typeof(string));
dt.Columns.Add("Company", typeof(string));
dt.Columns.Add("AddressLine1", typeof(string));
dt.Columns.Add("AddressLine2", typeof(string));
dt.Columns.Add("AddressLine3", typeof(string));
dt.Columns.Add("AddressLine4", typeof(string));
dt.Columns.Add("AddressLine5", typeof(string));
dt.Columns.Add("PostCode", typeof(string));
detailTable = new DataTable("Details");
detailTable.Columns.Add("OrderNumber", typeof(string));
detailTable.Columns.Add("LineNumber", typeof(int));
detailTable.Columns.Add("ProductCode", typeof(string));
detailTable.Columns.Add("ProductName", typeof(string));
detailTable.Columns.Add("OrderQty", typeof(int));
detailTable.Columns.Add("OutstandingQty", typeof(int));
detailTable.Columns.Add("DespatchedQty", typeof(string));
detailTable.PrimaryKey = new DataColumn[] { detailTable.Columns["OrderNumber"] };
#endregion
#region Fill the table
// read in the csv file
string[] csvRows = File.ReadAllLines(file);
string[] fields = null;
foreach (string csvRow in csvRows)
{
fields = csvRow.Split(',');
string orderNumber = fields[0].ToString();
string customerNumber = fields[2].ToString();
string Company = fields[3].ToString();
string AddressLine1 = fields[4].ToString();
string AddressLine2 = fields[5].ToString();
string AddressLine3 = fields[6].ToString();
string AddressLine4 = fields[7].ToString();
string AddressLine5 = fields[8].ToString();
string PostCode = fields[9].ToString();
int LineNumber = Convert.ToInt32(fields[1]);
string ProductCode = fields[10].ToString();
string ProductName = fields[11].ToString();
int OrderQty = Convert.ToInt32(fields[12]);
int OutstandingQty = Convert.ToInt32(fields[13]);
int DespatchedQty = Convert.ToInt32(fields[14]);
dt.Rows.Add(orderNumber, Company, AddressLine1, AddressLine2, AddressLine3, AddressLine4, AddressLine5,PostCode);
detailTable.Rows.Add(orderNumber, ProductCode, ProductName, OrderQty, OutstandingQty, DespatchedQty);
}
#endregion
var query = from row in detailTable.AsEnumerable()
group row by row.Field<string>("OrderNumber") into grp
select new DataClass()
{
OrderNumber = grp.Key,
Details = grp
};
OrderDespatchDetail detail = new OrderDespatchDetail();
DespatchDetails despatchDetail = new DespatchDetails();
string orderNo = string.Empty;
string custNo = string.Empty;
foreach (DataRow item in query)
{
DataRow found = dt.Rows.Find(item.Field<string>("OrderNumber"));
if (orderNo != found.Field<string>("OrderNumber"))
{
}
detail.LineNumber = item.Field<int>("LineNumber");
detail.ProductCode = item.Field<string>("ProductCode");
detail.ProductName = item.Field<string>("ProductName");
detail.Quantity = item.Field<int>("");
}
OrderDespatchRequest request = new OrderDespatchRequest();
request.despatchDetails = despatchDetail;
return SendOrderDespatch(request);
}
Could be well off the path with it.
Regards
Aidan
As an example the following should get you started.
Read the CSV File
var rows = (from row in File.ReadAllLines("Test.csv")
let item = row.Split(',')
select new
{
OrderNumber = item[0],
LineNumber = item[1],
CustomerID = item[2],
Company = item[3],
AddressLine1 = item[4],
AddressLine2 = item[5],
AddressLine3 = item[6],
AddressLine4 = item[7],
AddressLine5 = item[8],
PostCode = item[9],
ProductCode = item[10].ToString(),
ProductName = item[11].ToString(),
OrderQty = item[12],
OutstandingQty = item[13],
DespatchedQty = item[14]
}).ToList();
Group the data per order into a dynamic type.
var orders = from p in rows
group p by new { OrderNumber = p.OrderNumber, CustomerID = p.CustomerID } into g
select new { OrderNumber = g.Key.OrderNumber, CustomerID = g.Key.CustomerID, OrderLines = g.ToList() };
Create the XML file (please note the output xml will not match your exact requirement, but this example should get you going).
var xEle = new XElement("Orders",
from order in orders
select new XElement("Order",
new XAttribute("OrderNumber", order.OrderNumber),
new XElement("CustomerId", order.CustomerID)
, from line in order.OrderLines
select new XElement("Line", new XAttribute("ProductCode", line.ProductCode),
new XElement("OrderQty", line.OrderQty))));
xEle.Save("orders.xml");
Console.WriteLine("Converted to XML");

how to remove and add css class to a specific textbox inside gridview in c# asp.net?

Please tell me how to remove and add CssClass to a specific textbox inside gridview ?
This is what i have tried but it doesnot changee css for the textbox
my css in my .aspx page is :
<style type="text/css">
.erroramount
{
border:3px solid red
}
</style>
in my button click here is my code for gridview looping where depending upon the condition i want to change the border color of the textbox;
var result = (from f in dtCloned.AsEnumerable()
group f by f.Field<string>("AssetDescription") into g
select
new
{
AssetDescription = g.Key,
TotalAmount = g.Sum(r => r.Field<double?>("Amount"))
});
foreach (var aAsset in result.AsEnumerable())
{
if (aAsset.TotalAmount < 0)
{
foreach (GridViewRow arow in GridProjectDetails.Rows)
{
string AssetDescription = ((TextBox)arow.FindControl("TextAssetDescription")).Text;
if (AssetDescription == aAsset.AssetDescription)
{
((TextBox)arow.FindControl("TextAmount")).CssClass = "erroramount";
}
}
}
}
Your statement should work unless the code is not reachable or its not finding the control. It would have thrown exception if control was not found.There is an alternate way to set the class as well:
((TextBox)arow.FindControl("TextAmount")).Attributes["class"] = "erroramount";
Hi i got my output by removing the existing (default) css class and adding this css class with textbox. it worked.
Here is the complete code
protected void btnSubmit_Click(object sender, EventArgs e)
{
ValidateAmount();
}
private void ValidateAmount()
{
System.Data.DataTable dtGridData = new DataTable();
DataTable dtCloned = new DataTable();
dtGridData.Columns.Add("ID", typeof(string));
dtGridData.Columns.Add("DocumentNumber", typeof(string));
dtGridData.Columns.Add("NameOfOffsettingAccount", typeof(string));
dtGridData.Columns.Add("Amount", typeof(string));
dtGridData.Columns.Add("AssetDescription", typeof(string));
dtGridData.Columns.Add("Quantity", typeof(string));
dtGridData.Columns.Add("UnitOfMeasure", typeof(string));
foreach (GridViewRow row in GridProjectDetails.Rows)
{
string Id = ((TextBox)row.FindControl("ID")).Text;
string DocumentNumber = ((Label)row.FindControl("LabelDocumentNumber")).Text;
string NameOfOffsettingAccount = ((Label)row.FindControl("TextName")).Text;
string Amount = ((TextBox)row.FindControl("TextAmount")).Text;
string AssetDescription = ((TextBox)row.FindControl("TextAssetDescription")).Text;
string Quantity = ((TextBox)row.FindControl("TextQuantity")).Text;
string UnitOfMeasure = ((DropDownList)row.FindControl("DropDownUnitOfMeasure")).Text;
DataRow dr = dtGridData.NewRow();
dr["Id"] = Id;
dr["DocumentNumber"] = DocumentNumber;
dr["NameOfOffsettingAccount"] = NameOfOffsettingAccount;
if (Amount.Contains(','))
{
Amount = Amount.Replace(",", "");
}
dr["Amount"] = Amount;
dr["AssetDescription"] = AssetDescription;
dr["Quantity"] = Quantity;
dr["UnitOfMeasure"] = UnitOfMeasure;
dtGridData.Rows.Add(dr);
dtCloned = dtGridData.Clone();
dtCloned.Columns["Amount"].DataType = typeof(double);
foreach (DataRow arow in dtGridData.Rows)
{
dtCloned.ImportRow(arow);
}
}
var result = (from f in dtCloned.AsEnumerable()
group f by f.Field<string>("AssetDescription") into g
select
new
{
AssetDescription = g.Key,
TotalAmount = g.Sum(r => r.Field<double?>("Amount"))
});
foreach (var aAsset in result.AsEnumerable())
{
if (aAsset.TotalAmount < 0)
{
if (!lblMessage.Text.Contains("<br/> Total Amount cannot be negative for same asset - "
+ aAsset.AssetDescription.ToString()))
{
lblMessage.Text = lblMessage.Text + "\n" + "<br/> Total Amount cannot be negative for same asset - " + aAsset.AssetDescription.ToString();
lblMessage.Attributes.Add("style", "color:Red;font-weight:bold;");
lblMessage.Visible = true;
}
foreach (GridViewRow arow in GridProjectDetails.Rows)
{
string AssetDescription = ((TextBox)arow.FindControl("TextAssetDescription")).Text;
if (AssetDescription == aAsset.AssetDescription)
{
((TextBox)arow.FindControl("TextAmount")).CssClass =
((TextBox)arow.FindControl("TextAmount")).CssClass.Replace("amount", " ");
((TextBox)arow.FindControl("TextAmount")).CssClass = "erroramount";
}
}
}
}
}

Categories