My Table1 has some Header and Values:
KundeID KundeName Produkt Comment
1 Michael Jogurt "nichts"
2 Raj "Ich bin cool"
3 Gary Fanta "yahoo"
4 Miky Sprite
I want to change to Table2, make Values from Produkt as Header Columns:
KundeID KundeName Comment Jogurt Fanta Sprite
1 Michael "nichts" x
2 Raj "Ich bin cool"
3 Gary "yahoo" x
4 Miky x
My code for Table1:
DataTable table = new DataTable("Kunde");
table.Columns.Add("KundeID", typeof(Int32));
table.Columns.Add("KundeName", typeof(String));
table.Columns.Add("Produkt", typeof(String));
DataTable comment = new DataTable("Comment");
comment.Columns.Add("KundeName", typeof(String));
comment.Columns.Add("Comment", typeof(String));
DataSet ds = new DataSet("DataSet");
ds.Tables.Add(table);
ds.Tables.Add(comment);
object[] o1 = { 1, "Michael", "Jogurt" };
object[] o2 = { 2, "Raj" };
object[] o3 = { 3, "Gary", "Fanta" };
object[] o4 = { 4, "Miky", "Sprite" };
object[] c1 = { "Raj", "Ich bin cool" };
object[] c2 = { "Gary", "yahoo" };
object[] c3 = { "Michael", "nichts" };
table.Rows.Add(o1);
table.Rows.Add(o2);
table.Rows.Add(o3);
table.Rows.Add(o4);
comment.Rows.Add(c1);
comment.Rows.Add(c2);
comment.Rows.Add(c3);
var results = from table1 in table.AsEnumerable()
join table2 in comment.AsEnumerable()
on table1.Field<string>("KundeName") equals table2.Field<string>("KundeName") into prodGroup
from table4 in prodGroup.DefaultIfEmpty()
select new
{
KundeID = table1.Field<Int32?>("KundeID"),
KundeName = table1.Field<String>("KundeName"),
Produkt = table1.Field<String>("Produkt"),
Comment = table4 != null ? table4.Field<String>("Comment") : null,
};
dataGridView1.DataSource = results.ToList();
How can I take Value from "Produkt" and make it Header? thank you guys for helping
This should do the trick regardless of how many different products come up. It's pretty short and concise.
// build the new data table
var result = new DataTable();
result.Columns.Add("KundeID", typeof(Int32));
result.Columns.Add("KundeName", typeof(String));
result.Columns.Add("Comment", typeof(String));
result.Columns.AddRange(
(from c in
(from r in table.AsEnumerable()
where !r.IsNull("Produkt") && !string.IsNullOrEmpty(r.Field<string>("Produkt"))
select r.Field<string>("Produkt")).Distinct() // added DISTINCT
select new DataColumn(c, typeof(bool))).ToArray()
);
foreach (var r in results)
{
var productIndex = result.Columns.IndexOf(r.Produkt);
var vals = new List<object>() { r.KundeID, r.KundeName, r.Comment };
for (int i = 3; i < result.Columns.Count; i++)
{
if (i == productIndex)
{
vals.Add(true);
}
else
{
vals.Add(false);
}
}
result.LoadDataRow(vals.ToArray(), true);
}
var products = table.AsEnumerable()
.GroupBy(c => c["Produkt"])
.Where(g => !(g.Key is DBNull))
.Select(g => (string)g.Key)
.ToList();
var newtable = table.Copy();
products.ForEach(p=>newtable.Columns.Add(p,typeof(bool)));
foreach (var row in newtable.AsEnumerable())
{
if (!(row["Produkt"] is DBNull)) row[(string)row["Produkt"]] = true;
}
newtable.Columns.Remove("Produkt");
Try following...this may help you....
DataTable table = new DataTable("Kunde");
table.Columns.Add("KundeID", typeof(Int32));
table.Columns.Add("KundeName", typeof(String));
table.Columns.Add("Produkt", typeof(String));
table.Columns.Add("Comment", typeof(String));
object[] o1 = { 1, "Michael", "Jogurt", "nichts" };
object[] o2 = { 2, "Raj","","Ich bin cool" };
object[] o3 = { 3, "Gary", "Fanta","yahoo" };
object[] o4 = { 4, "Miky", "Sprite","" };
table.Rows.Add(o1);
table.Rows.Add(o2);
table.Rows.Add(o3);
table.Rows.Add(o4);
Dictionary<int,string> dictObj=new Dictionary<int, string>();
for (int i = 0; i < table.Rows.Count; i++)
{
dictObj.Add(Convert.ToInt32(table.Rows[i][0].ToString()), table.Rows[i][2].ToString());
}
foreach (var obj in dictObj)
{
if (string.IsNullOrEmpty(obj.Value))
{
table.Columns.Add(obj.Value, typeof(String));
DataRow row = table.Rows[obj.Key];
row[obj.Value] = "X";
}
}
Related
I have Data Table with the following data
Number Type Order count
1 1 R 1
1 1 R 1
1 1 R 1
1 2 R 1
I am looking to get to this result
Number Type Order count
1 1 R 3
1 2 R 1
How can I group by three columns
var result = dt.AsEnumerable()
.GroupBy(x => {x.Field<string>("Number"))//need to group by Type and order also need to sum te total counts
rgoal
Your question made me curious, so I did some digging on Stack Overflow.
esc's answer appears will also solve your issue. It is posted under: How do I use SELECT GROUP BY in DataTable.Select(Expression)?:
Applying his method to your problem gave me this solution:
DataTable dt2 = dt.AsEnumerable()
.GroupBy(r => new { Number = r["Number"], Type = r["Type"], Order = r["Order"] })
.Select(g =>
{
var row = dt.NewRow();
row["Number"] = g.Key.Number;
row["Type"] = g.Key.Type;
row["Order"] = g.Key.Order;
row["Count"] = g.Count();
return row;
}).CopyToDataTable();
This will return a DataTable matching the schema of the input DataTable with the grouping and counts you requested.
Here is the full code I use to verify in LINQPad:
DataTable dt = new DataTable("Demo");
dt.Columns.AddRange
(
new DataColumn[]
{
new DataColumn ( "Number", typeof ( int ) ),
new DataColumn ( "Type", typeof ( int ) ),
new DataColumn ( "Order", typeof ( string ) ),
new DataColumn ( "Count", typeof ( int ) )
}
);
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,1,"R", 1 });
dt.Rows.Add(new object[] { 1,2,"R", 1 });
DataTable dt2 = dt.AsEnumerable()
.GroupBy(r => new { Number = r["Number"], Type = r["Type"], Order = r["Order"] })
.Select(g =>
{
var row = dt.NewRow();
row["Number"] = g.Key.Number;
row["Type"] = g.Key.Type;
row["Order"] = g.Key.Order;
row["Count"] = g.Count();
return row;
}).CopyToDataTable();
foreach (DataRow row in dt2.Rows)
{
for (int i = 0; i < dt2.Columns.Count; i++)
Console.Write("{0}{1}",
row[i], // Print column data
(i < dt2.Columns.Count - 1)? " " : Environment.NewLine); // Print column or row separator
}
Here are the results:
1 1 R 3
1 2 R 1
I joined a 2 data tables based on the EMP column and used copytodatatable, however when i load the new datatable into datagridview it only shows the joined columns(salarydt) from the query, why is this??
var collection = from p in dt.AsEnumerable()
join q in salaryDT.AsEnumerable() on p.Field<int>("Emp") equals q.Field<int>("Emp1") into UP
from t in UP
select t;
DataTable resultdt = new DataTable();
dt = collection.CopyToDataTable();
DataTable itself is perfectly geared to merging itself with another data table, using its, well, Merge method. Here's a litte example:
var dt1 = new DataTable("a");
dt1.Columns.Add("ID", typeof(int));
dt1.Columns.Add("Item1", typeof(int));
dt1.PrimaryKey = new[] { dt1.Columns[0] };
var dt2 = new DataTable("a");
dt2.Columns.Add("ID", typeof(int));
dt2.Columns.Add("Item2", typeof(int));
dt2.PrimaryKey = new[] { dt2.Columns[0] };
for (int i = 0; i < 10; i++)
{
dt1.Rows.Add(new object[] { i, i });
dt2.Rows.Add(new object[] { i, i + 10 });
}
dt1.Merge(dt2);
Now dt1 has three columns, ID, Item1, and Item2.
ID Item1 Item2
0 0 10
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
6 6 16
7 7 17
8 8 18
9 9 19
Maybe what you should to do is just return a custom list of items:
Option 1
var data = new Employee[] { new Employee { Id = 1, Name = "John Doe" } };
var data2 = new Salary[] { new Salary { Id = 1, Wage = "$ 50,000.00" } };
var collection = from p in data
join q in data2 on p.Id equals q.Id
select new { Id = p.Id, Name = p.Name, Wage = q.Wage };
Please check the example: link
Option 2
var data = new Employee[] { new Employee { Id = 1, Name = "John Doe" } };
var data2 = new Salary[] { new Salary { Id = 1, Wage = "$ 50,000.00" } };
var collection = from p in data
join q in data2 on p.Id equals q.Id
select new { p, q };
Seems like this is the kind of thing that would have already been answered but I'm unable to find it.
I have following table:
Id Parent Text
-----------------------
1 NULL A
2 1 B
3 2 C
4 3 D
5 NULL E
6 5 F
7 6 G
Now I want to have the result like this: (List<string>)
A
A > B
A > B > C
A > B > C > D
E
E > F
E > F > G
But the problem is that, this project that I am working on it, uses database first, I mean there's no navigation property, Parent is type of string not IEnumerable<T>.
What I have done so far:
var list = new List<string>();
string e2 = string.Empty;
foreach (var item in query)
{
string e1 = string.Empty;
if (item.Parent == null)
{
list.Add(p.Text);
e2 = item.Text;
}
else
{
foreach (var subItem in query.Where(t => t.Id == p.Parent))
{
if (subItem.Id != 1)
{
e1 = e2 + " > " + subItem.Text;
}
else
{
e1 = subItem.Text;
}
}
list.Add(e1 + " > " + p.Text);
}
}
Use recursive algorithm
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static List<string> list = new List<string>();
static DataTable dt = new DataTable();
static void Main(string[] args)
{
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Parent", typeof(int));
dt.Columns["Parent"].AllowDBNull = true;
dt.Columns.Add("Text", typeof(string));
dt.Rows.Add(new object[] {1, null, "A"});
dt.Rows.Add(new object[] {2, 1, "B"});
dt.Rows.Add(new object[] {3, 2, "C"});
dt.Rows.Add(new object[] {4, 3, "D"});
dt.Rows.Add(new object[] {5, null, "E"});
dt.Rows.Add(new object[] {6, 5, "F"});
dt.Rows.Add(new object[] {7, 6, "G"});
GetRecursiveChildren(null, new List<string>());
foreach (string row in list)
{
Console.WriteLine(row);
}
Console.ReadLine();
}
static void GetRecursiveChildren(int? parent, List<string> parents)
{
foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("Parent") == parent))
{
string text = row.Field<string>("Text");
List<string> newParents = new List<string>();
newParents.AddRange(parents);
newParents.Add(text);
list.Add(string.Join(" > ",newParents));
int child = row.Field<int>("Id");
GetRecursiveChildren(child, newParents);
}
}
}
}
This works for me:
var source = new []
{
new { Id = 1, Parent = (int?)null, Text = "A" },
new { Id = 2, Parent = (int?)1, Text = "B" },
new { Id = 3, Parent = (int?)2, Text = "C" },
new { Id = 4, Parent = (int?)3, Text = "D" },
new { Id = 5, Parent = (int?)null, Text = "E" },
new { Id = 6, Parent = (int?)5, Text = "F" },
new { Id = 7, Parent = (int?)6, Text = "G" }
};
var lookup = source.ToLookup(x => x.Parent);
Func<int?, IEnumerable<string>> recurse = null;
recurse = p =>
lookup[p].SelectMany(x => new [] { x.Text }
.Concat(recurse(x.Id).Select(y => $"{x.Text} > {y}")));
foreach (string x in recurse(null))
{
Console.WriteLine(x);
}
I get:
A
A > B
A > B > C
A > B > C > D
E
E > F
E > F > G
I have a datatable that looks like below
My result Should be A=40% , B=60% .. ie 2/5 and 3/5
Group name can be A, B, C, etc...
How can i calculate the figures based on that datatable values??
You could use LINQ and cast it to a dictionary:
DataTable dt = new DataTable("test1");
dt.Columns.AddRange(new DataColumn[] { new DataColumn("TASKID"), new DataColumn("GROUPID"), new DataColumn("GROUPNAME") });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 13, 3, "B" });
dt.Rows.Add(new object[] { 12, 2, "A" });
dt.Rows.Add(new object[] { 14, 3, null });
dt.Rows.Add(new object[] { 15, 3, "B" });
var query = (from DataRow row in dt.Rows
group row by row["GROUPNAME"] into g
select g).ToDictionary(x => (x.Key.ToString() == "" ? "*" : x.Key.ToString()), x => (int)((x.Count() * 100) / dt.Rows.Count));
Iterate through the dictionary to display the values:
foreach(KeyValuePair<string,int> kvp in query)
Console.WriteLine(kvp.Key + " - " + kvp.Value.ToString());
The output:
A - 40
B - 40
* - 20
The percentage is cast as an int. simply change (int)((x.Count() * 100) / dt.Rows.Count) if you need more accurate values.
A simple way, through loop. The following should be similar to the one you require.
//Simulated datatable
DataTable table1 = new DataTable();
table1.Columns.Add(new DataColumn("TaskID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupID", typeof(int)));
table1.Columns.Add(new DataColumn("GroupName", typeof(String)));
//Entered test values
DataRow dr1 = null;
dr1 = table1.NewRow();
dr1["TaskID"] = 12;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 13;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 14;
dr1["GroupID"] = 2;
dr1["GroupName"] = "A";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 15;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
dr1 = table1.NewRow();
dr1["TaskID"] = 16;
dr1["GroupID"] = 3;
dr1["GroupName"] = "B";
table1.Rows.Add(dr1);
//solution starts from here
Dictionary<string, int> totalCount = new Dictionary<string, int>();
for (int i = 0; i < table1.Rows.Count; i++)
{
if (totalCount.Keys.Contains(table1.Rows[i]["GroupName"].ToString()))
{
int currVal = totalCount[table1.Rows[i]["GroupName"].ToString()];
totalCount[table1.Rows[i]["GroupName"].ToString()] = currVal + 1;
}
else
{
totalCount[table1.Rows[i]["GroupName"].ToString()] = 1;
}
}
foreach (var item in totalCount)
{
MessageBox.Show(item.Value.ToString());
}
OR
//solution starts from here
var data = table1.AsEnumerable().GroupBy(m => m.Field<string>("GroupName")).Select(grp => new
{
GroupName = grp.Key,
Count = (int)grp.Count()
}).ToList();
Hope this helps
Use Linq
var data=datatable.AsEnumerable().GroupBy(m => m.Field<string>("GROUPNAME")).Select(grp => new
{
GROUPNAME= grp.Key,
Count = (int)grp.Count()
});
I am iterating on a lot of strings and I want to fill my first(and only) 3 Columns with each result and then start again in a new row. like:
A | B | C
------+--------+------
"DOG" | "CAT" | "FISH"
"FDF" | "AAA" | "RRR"
AND SO ON....
Basically after each row is "full" open new row.
HtmlNodeCollection tables = doc.DocumentNode.SelectNodes("//table");
HtmlNodeCollection rows = tables[2].SelectNodes(".//tr");
DataTable dataTable = new DataTable();
dataTable.Columns.Add("A", typeof(string));
dataTable.Columns.Add("B", typeof(string));
dataTable.Columns.Add("C", typeof(string))
try like this
for (int i = 0; i < rows .Count(); i++)
{
DataRow datarowObj= dataTable .NewRow();
datarowObj["A"] = yourValue;
datarowObj["B"] = yourValue;
datarowObj["C"] = yourValue;
dataTable.Rows.Add(datarowObj);
}
You could use Linq's GroupBy to split the long list into groups of 3:
sample-data:
DataTable table = new DataTable();
table.Columns.Add("Col1");
table.Columns.Add("Col2");
table.Columns.Add("Col3");
List<string> longList = Enumerable.Range(1, 99).Select(i => "row " + i).ToList();
group the long list into parts of three:
var groupsWithThree = longList
.Select((s, i) => new { Str = s, Index = i })
.GroupBy(x => x.Index / 3);
add them to the table:
foreach (var group3 in groupsWithThree)
table.Rows.Add(group3.First().Str, group3.ElementAt(1).Str, group3.Last().Str);
Note that it presumes that the list is divisible by three.
Manage with DataRoxw, for instance, after adding an empty DataRow to your DataTable :
DataRow row = table.Rows[0];
foreach (object item in row.ItemArray)
{
?
dataTable.Rows.Add(new object[] { "A1", "B1", "C1" })
// Alternatively
object[] arr = new object[] { "A2", "B2", "C2" };
dataTable.Rows.Add(arr);