I have a question that's similar to yesterday's question.
I've got this List<object[]>
List<object[]> olst = new List<object[]>();
olst.Add(new object[] { "AA1", "X", 1, 3.50 });
olst.Add(new object[] { "AA2", "Y", 2, 5.20 });
olst.Add(new object[] { "AA2", "Y", 1, 3.50 });
olst.Add(new object[] { "AA1", "X", 1, 3.20 });
olst.Add(new object[] { "AA1", "Y", 2, 5.30 });
I need to produce List<object[]> to hold this:
"AA1", "X", 2, 6.70
"AA2", "Y", 3, 8.70
"AA1", "Y", 2, 5.30
In other words, I need to group olst by the 1st and 2nd elements of each object[] and sum 3rd and 4th.
I could use a for loop, but I was hoping someone could help me using lambda expressions and/or linq to accomplish this.
List<object[]> olst = new List<object[]>();
olst.Add(new object[] { "AA1", "X" });
olst.Add(new object[] { "AA2", "Y" });
olst.Add(new object[] { "AA2", "Y" });
olst.Add(new object[] { "AA1", "X" });
olst.Add(new object[] { "AA1", "Y" });
var result = from ol in olst
group ol by new {p1 = ol[0], p2 = ol[1]}
into g
select g.First();
Something like this?
You need to group by an anonymous type, then sum the third and fourth columns:
List<object[]> grouped = olst
.GroupBy(o => new { Prop1 = o[0].ToString(), Prop2 = o[1].ToString() })
.Select(o => new object[]
{
o.Key.Prop1,
o.Key.Prop2,
o.Sum(x => (int)x[2]),
o.Sum(x => (double)x[3])
})
.ToList();
As suggested in the comments, I would go with Tuple and maybe use HashSet instead, since it will only append if item doesn't exist (also, it is fast). If you add items to hashset, there's no need to select distinct as long as your type provides necessary Equals and GetHashCode methods.
Something like this:
var olst = new HashSet<Tuple<string,string>>();
olst.Add(Tuple.Create("AA1", "X"));
olst.Add(Tuple.Create("AA1", "X"));
olst.Add(Tuple.Create("AA2", "Y"));
olst.Add(Tuple.Create("AA2", "Y"));
If you need you can convert it to list. Here's an example:
olst.ToList().ForEach(x=> Console.WriteLine(x.Item1 + " " + x.Item2));
Will print out
AA1 X
AA2 Y
Related
I have two lists:
list1 = [a,b,c,4]
list2 = [1,23,5,6]
Now I need to create an anonymous object using linq lambda.
Something like.
list1 = DataTable.AsEnumerable().toList();
list2 = DataTable.AsEnumerable().toList();
var result = list1.Where(x => x.Field<int>(1) == 2018).Select(x => new[] {
new {x = "XYZ", y = x[0], z = list2[0]},
....}
}
How do I go about doing this?
You need Zip Linq method, consider this example:
int[] list1 = {1, 2, 3};
string[] list2 = {"a", "b", "c"};
var result = list1.Zip(list2, (i, s) => new {y = i, z = i});
Your code is fine, it just needs some small fixes:
string [] list1 = { "a", "b", "c", "4" };
int[] list2 = { 1, 23, 5, 6 };
object[] list3 = { "test", DateTime.Now, 56 };
var result = list1.Where(x => x == "a").Select(x =>
new { x = "XYZ", y = x[0], z = list2[0], t = list3[1] }).ToList();
I need to compare two datatables which are having same schema and move the differences into another datatable. Below is my code which is not working fine:
DataTable dt1 = new DataTable("TableChanged");
dt1.Columns.Add("StateID",typeof(int));
dt1.Columns.Add("StateInitial");
dt1.Columns.Add("IsActive");
dt1.Rows.Add(new object[] { 10, "GA", 1 });
dt1.Rows.Add(new object[] { 11, "HI", 0 });
dt1.Rows.Add(new object[] { 12, "ID", 1 });
dt1.Rows.Add(new object[] { 13, "IL", 1 });
dt1.Rows.Add(new object[] { 14, "IN", 0 });
dt1.Rows.Add(new object[] { 15, "IA", 1 });
dt1.Rows.Add(new object[] { 23, "MN", 0 });
DataTable dt2 = new DataTable("TableOriginal");
dt2.Columns.Add("StateID", typeof(int));
dt2.Columns.Add("StateInitial");
dt2.Columns.Add("IsActive");
dt2.Rows.Add(new object[] { 10, "GA", 1 });
dt2.Rows.Add(new object[] { 11, "HI", 1 });
dt2.Rows.Add(new object[] { 12, "ID", 1 });
dt2.Rows.Add(new object[] { 13, "IL", 0 });
dt2.Rows.Add(new object[] { 14, "IN", 1 });
dt2.Rows.Add(new object[] { 15, "IA", 1 });
dt2.Rows.Add(new object[] { 23, "MN", 1 });
var matched = from table1 in dt1.AsEnumerable()
join table2 in dt2.AsEnumerable() on table1.Field<int>("StateID") equals table2.Field<int>("StateID")
//where table1.Field<object>("IsActive") == "0"
where table1.Field<string>("StateInitial") == table2.Field<string>("StateInitial") || table1.Field<object>("IsActive") == table2.Field<object>("IsActive")
select table1;
var missing = from table1 in dt1.AsEnumerable()
where !matched.Contains(table1)
select table1;
After comparison, I want result like:
StateID|StateInitial|IsActive
11 "HI" 0
13 "IL" 1
14 "IN" 0
23 "MN" 0
You can use DataRowComparer.Default, which compares every field of a DataRow, for the LINQ methods Intersect and Except. The latter gives you the missing rows, your desired result:
DataRowComparer<DataRow> fieldComparer = DataRowComparer.Default;
IEnumerable<DataRow> matched = dt1.AsEnumerable().Intersect(dt2.AsEnumerable(), fieldComparer);
IEnumerable<DataRow> missing = dt1.AsEnumerable().Except(dt2.AsEnumerable(), fieldComparer);
If you want to add the missing rows into a third table, you could use:
DataTable result = missing.CopyToDataTable();
But i suggest to use a different way because that throws an exception if there were no missing rows:
DataTable result = dt1.Clone(); // empty, same schema
foreach(DataRow row in missing)
result.ImportRow(row);
Suppose I have two arrays of always equal length that could look like this:
{"A", "C", "A", "A", "B", "B", "A", "A" }
{ 1, 1, 2, 3, 1, 10, 5, 7 }
Data is paired by array index.
I wish to use LINQ to produce a result that looks like below:
A: { 1, 2, 3, 5, 7 }
B: { 1, 10 }
C: { 1 }
How can I accomplish that?
The arrays come from http request parameters. The letters applies to database names and the integers are ids in a table in the database. Next step is to connect to each database and get some data for each id.
You can first Zip them, and then group them. Use the grouped result to construct a dictionary, or whatever type you want.
string[] first = { "A", "C", "A", "A", "B", "B", "A", "A" };
int[] second = { 1, 1, 2, 3, 1, 10, 5, 7 };
var list = first.Zip(second, (f, s) => new { First = f, Second = s });
Dictionary<string, int[]> d = list.GroupBy(i => i.First)
.ToDictionary(k => k.Key, v => v.Select(val => val.Second)
.ToArray()
);
Try this
string[] s = { "A", "C", "A", "A", "B", "B", "A", "A" };
int[] t = { 1, 1, 2, 3, 1, 10, 5, 7 };
var results = s.Select((x, i) => new { s = x, t = t[i] })
.GroupBy(x => x.s).ToList();
I have data table having rows like
ID Name
2 A
4 B
3 C
5 D
1 E
List order = new List() { "1", "3", "2", "5", "4" }
--------------order by list-----------------
ID Name
1 E
3 C
2 A
5 D
4 B
can anyone help to implement this.. I am using DataTable in Winforms.
Another solution to the already given ones, would be to loop your order list and then sort your source list.
// source list
List<Foo> lSource = new List<Foo>() {
new Foo() { ID = 2, Name = "A" },
new Foo() { ID = 4, Name = "B" },
new Foo() { ID = 3, Name = "C" },
new Foo() { ID = 5, Name = "D" },
new Foo() { ID = 1, Name = "E" },
};
// order list
List<int> order = new List<int>() { 1, 3, 2, 5, 4 };
// loop order list and sort source list
order.ForEach(x =>
{
lSource = lSource.OrderBy(g => g.ID == x).ToList();
});
// set datasource
dataGridView1.DataSource = lSource;
I just added a class Foo containing an int ID and a string Name, because you didn't share your whole code.
I think you can join your order and your datatable with AsEnumerable method and on on part you can equalize both of them and select rows, then you can generate a DataTable from that query with CopyToDataTable method.
var dt = new DataTable();
var dc = new DataColumn() { ColumnName = "ID", DataType = typeof(string) };
dt.Columns.Add(dc);
dc = new DataColumn() { ColumnName = "Name", DataType = typeof(string) };
dt.Columns.Add(dc);
dt.Rows.Add(new object[] { "2", "A" });
dt.Rows.Add(new object[] { "4", "B" });
dt.Rows.Add(new object[] { "3", "C" });
dt.Rows.Add(new object[] { "5", "D" });
dt.Rows.Add(new object[] { "1", "E" });
List<string> order = new List<string>() { "1", "3", "2", "5", "4" };
var query = from item in order
join row in dt.AsEnumerable() on item equals row.Field<string>("ID")
select row;
var result = query.CopyToDataTable();
result will be;
I'm not sure this is the best way or not but this seems to fit with your case.
You can join both lists (the one with items and the one with sorted id's) and then select the items:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<Item>{
new Item { Id = 2, Text = "A" },
new Item { Id = 4, Text = "B" },
new Item { Id = 3, Text = "C" },
new Item { Id = 5, Text = "D" },
new Item { Id = 1, Text = "E" }
};
var sortorder = new List<int> { 1, 3, 2, 5, 4 };
var sortedlist = sortorder.Join(list, x => x, y => y.Id, (x,y) => y);
foreach(var item in sortedlist)
Console.WriteLine("{0} {1}", item.Id, item.Text);
}
}
I have a list of List<Tuple<string[], double[]>>
List<Tuple<string[], double[]>> tt = new List<Tuple<string[], double[]>>();
var t1 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 2, 3, 0 });
var t2 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 0, 3, 1 });
var t3 = new Tuple<string[], double[]>(
new string[] { "java", "c#", "nn" },
new double[] { 2, 1, 0 });
tt.Add(t1);
tt.Add(t2);
tt.Add(t3);
Lets say I want to divide each element in the double[] by the total counts non-zero counts in the columns. I would get the following results
t1 2/2, 3/3 0/1
t2 0/2, 3/3 1/1
t3 2/2, 1/3 0/1
Here is what I tried but it counts the row totals instead of the columns
var XX = (from tuples in tt
let rows = tuples.Item2.ToArray()
let result = rows.Select(x => x/rows.Count(i => i != 0)).ToArray()
select new Tuple<string[], double[]>(tuples.Item1, result)
).ToList();
What you are trying to do can be achieved with the following LINQ query:
List<Tuple<string[], double[]>> result = tt.Select(x =>
Tuple.Create(
x.Item1,
x.Item2.Select((y, i) => y / tt.Count(z => z.Item2[i] > 0))
.ToArray())).ToList();
Here are the resultant doubles printed to console: