I am stuck in a problem where I need to convert a list into Dictionary > BsonDocument to import in MongoDB.
The list has the name of column and the values to insert in that column. But I am getting key already exits exception as soon the compiler enter in loop. Any suggestion?
void Main()
{
List<ListRow> myList = new List<ListRow>();
myList.Add(new ListRow { columnName = "column1", results = new List<string> { "a1", "b1", "c1" } });
myList.Add(new ListRow { columnName = "column2", results = new List<string> { "a2", "b2", "c2" } });
myList.Add(new ListRow { columnName = "column3", results = new List<string> { "a3", "b3", "c3" } });
List<BsonDocument> batch = new List<BsonDocument>();
foreach (var row in myList)
{
var dictionary = row.results.ToDictionary(x => row.columnName, x => x);
batch.Add(dictionary);
}
// Print batch
// Add to MongoDB
}
public class ListRow
{
public string columnName { get; set; }
public List<string> results { get; set; }
}
Expected result to pull
You are trying to make an entry in the iteration. ToDictionary aims for create the whole dictionary.
class Program
{
static void Main(string[] args)
{
List<ListRow> myList = new List<ListRow>
{
new ListRow {columnName = "column1", results = new List<string> {"a1", "b1", "c1"}},
new ListRow {columnName = "column2", results = new List<string> {"a2", "b2", "c2"}},
new ListRow {columnName = "column3", results = new List<string> {"a3", "b3", "c3"}}
};
BsonDocument batch = myList.ToDictionary(x => x.columnName, x => x.results).ToBsonDocument();
// Print batch
// Add to MongoDB
}
}
public class ListRow
{
public string columnName { get; set; }
public List<string> results { get; set; }
}
Ok. If I understand the problem correctly, you want to first transpose the matrix of
"a1", "b1", "c1"
"a2", "b2", "c2"
"a3", "b3", "c3"
than name the columns with column1, column2, column3, etc.. For the transpose problem I got this solution.
From there I worked out this solution, where I needed a root node, which is not clear how should look like from the question>
class Program
{
static void Main(string[] args)
{
List<ListRow> myList = new List<ListRow>
{
new ListRow {columnName = "column1", results = new List<string> {"a1", "b1", "c1"}},
new ListRow {columnName = "column2", results = new List<string> {"a2", "b2", "c2"}},
new ListRow {columnName = "column3", results = new List<string> {"a3", "b3", "c3"}}
};
var result = myList
.SelectMany(listRow => listRow.results.Select((item, index) => new {item, index}))
.GroupBy(i => i.index, i => i.item)
.Select(g => g.Select((x, index) => new {Col = myList[index].columnName, Value = x})
.ToDictionary(x => x.Col, x => x.Value))
.ToList();
BsonDocument batch = new Dictionary<string, List<Dictionary<string, string>>> {{"root", result}}
.ToBsonDocument();
// {{ "root" : [{ "column1" : "a1", "column2" : "a2", "column3" : "a3" }, { "column1" : "b1", "column2" : "b2", "column3" : "b3" }, { "column1" : "c1", "column2" : "c2", "column3" : "c3" }] }}
// or just
BsonArray batchPart = BsonArray.Create(result);
// {[{ "column1" : "a1", "column2" : "a2", "column3" : "a3" }, { "column1" : "b1", "column2" : "b2", "column3" : "b3" }, { "column1" : "c1", "column2" : "c2", "column3" : "c3" }]}
// Print batch
// Add to MongoDB
}
}
public class ListRow
{
public string columnName { get; set; }
public List<string> results { get; set; }
}
Your key : row.columName is repeated when the list is flatten to a dictionary. You can try to generate an unique key for each list item.
List<BsonDocument> batch = new List<BsonDocument>();
foreach (var row in myList)
{
var i = 0;
var dictionary = row.results.ToDictionary(x => $"{row.columnName}_{++i}", x => x);
batch.Add(dictionary);
}
Related
List object1
[ { "empId":10001, "empName":"test1" }, { "empId":10002, "empName":"test2" } ]
List object2
[ { "empId":10001, "emailAddress":"test1#mail.com" }, { "empId":10002, "emailAddress":"test2#mail.com" } ]
Trying to get the merge result which matches "empId" in both objects.
Result
[
{
"empId":10001,
"empName":"test1",
"emailAddress":"test1#mail.com"
},
{
"empId":10002,
"empName":"test2",
"emailAddress":"test2#mail.com"
}
]
I have tried https://www.newtonsoft.com/json/help/html/MergeJson.htm. but not able to do the matching logic "empId"
Here is some code that will Join and Merge, working here.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
var list1 = new[]
{
new { empId = 10001, empName = "test1" },
new { empId = 10002, empName = "test2" }
};
var list2 = new[]
{
new { empId = 10001, emailAddress = "test1#mail.com" },
new { empId = 10002, emailAddress = "test2#mail.com" }
};
var results1 = list1.MergeJoin(list2, e => e.empId);
Console.WriteLine($"{nameof(results1)}:");
Console.WriteLine(JsonConvert.SerializeObject(results1, Formatting.Indented));
Console.WriteLine();
IList<dynamic> dynamicList1 = new List<dynamic>
{
new { empId = 10001, empName = "test1", utterance = "wibble" },
new { empId = 10002, empName = "test2", expression = "bemused" }
};
IList<dynamic> dynamicList2 = new List<dynamic>
{
new { empId = 10001, emailAddress = "test1#mail.com", IQ = "moron" },
new { empId = 10002, emailAddress = "test2#mail.com", smell = "cheesy" }
};
var results2 = dynamicList1.MergeJoin(dynamicList2, e => e.empId);
Console.WriteLine($"{nameof(results2)}:");
Console.WriteLine(JsonConvert.SerializeObject(results2, Formatting.Indented));
}
}
public static class Extensions
{
public static IEnumerable<dynamic> MergeJoin<TKey>(
this IEnumerable<dynamic> outer,
IEnumerable<dynamic> inner,
Func<dynamic, TKey> keyAccessor)
{
return outer.Join(
inner,
keyAccessor,
keyAccessor,
Merge);
}
public static dynamic Merge(dynamic left, dynamic right)
{
IDictionary<string, object> dictionary1 = GetKeyValueMap(left);
IDictionary<string, object> dictionary2 = GetKeyValueMap(right);
var result = new ExpandoObject();
var d = result as IDictionary<string, object>;
foreach (var pair in dictionary1.Concat(dictionary2))
{
d[pair.Key] = pair.Value;
}
return result;
}
private static IDictionary<string, object> GetKeyValueMap(object values)
{
if (values == null)
{
return new Dictionary<string, object>();
}
var map = values as IDictionary<string, object>;
if (map != null)
{
return map;
}
map = new Dictionary<string, object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
map.Add(descriptor.Name, descriptor.GetValue(values));
}
return map;
}
}
This should output,
results1:
[
{
"empId": 10001,
"empName": "test1",
"emailAddress": "test1#mail.com"
},
{
"empId": 10002,
"empName": "test2",
"emailAddress": "test2#mail.com"
}
]
results2:
[
{
"empId": 10001,
"empName": "test1",
"utterance": "wibble",
"emailAddress": "test1#mail.com",
"IQ": "moron"
},
{
"empId": 10002,
"empName": "test2",
"expression": "bemused",
"emailAddress": "test2#mail.com",
"smell": "cheesy"
}
]
The Merge() function you are using is not the only thing you need. You need LINQ's Join() to "merge" the two lists and then Merge() to merge individual items:
var xs = JArray
.Parse(#"[
{""empId"": 10001, ""empName"": ""test1""},
{""empId"": 10002, ""empName"": ""test2""}
]")
.Values<JObject>();
var ys = JArray
.Parse(#"[
{""empId"": 10001, ""emailAddress"": ""test1#mail.com""},
{""empId"": 10002, ""emailAddress"": ""test2#mail.com""}
]")
.Values<JObject>();
var merged = xs.Join(
ys,
x => x["empId"],
y => y["empId"],
(x, y) => { x.Merge(y); return x; });
Note that you can probably just cast the dynamic types back to JObject for much easier handling.
I have a List<string> list1, example values:
var list1 = new List<string>()
{
"123", "1234", "12345",
};
I have a class:
public class TestClass {
public string name{ get; set; }
public int count{ get; set; }
}
and I have a List<TestClass> list2, example values:
var list2 = new List<TestClass>()
{
new TestClass() { name = "12", count = 0 },
new TestClass() { name = "123", count = 5 },
new TestClass() { name = "1234", count = 20 },
};
I want to merge list1 and list2 and the result should be:
name count
12 0
123 5
1234 20
12345 0
This works nicely:
var list1 = new List<string>()
{
"123", "1234", "12345",
};
var list2 = new List<TestClass>()
{
new TestClass() { name = "12", count = 0 },
new TestClass() { name = "123", count = 5 },
new TestClass() { name = "1234", count = 20 },
};
var merged =
list2
.Concat(list1.Select(x => new TestClass() { name = x, count = 0 }))
.GroupBy(x => x.name)
.SelectMany(x => x.Take(1))
.ToList();
It gives me:
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<TestClass> lst1 = new List<TestClass>();
lst1.Add(new TestClass(){name="One", count = 1});
lst1.Add(new TestClass(){name="Two", count = 2});
lst1.Add(new TestClass(){name="Three", count = 3});
List<TestClass> lst2 = new List<TestClass>();
lst2.Add(new TestClass(){name="Four", count = 4});
lst2.Add(new TestClass(){name="Two", count = 2});
lst2.Add(new TestClass(){name="Three", count = 3});
var unionlst = lst1.Union(lst2, new TestClassComparer ());
foreach(var x in unionlst){
Console.WriteLine(x.name + ","+x.count);
}
}
class TestClassComparer : IEqualityComparer<TestClass>
{
public bool Equals(TestClass p1, TestClass p2)
{
return p1.name == p2.name && p1.count == p2.count;
}
public int GetHashCode(TestClass p)
{
return p.count;
}
}
public class TestClass {
public string name{ get; set; }
public int count{ get; set; }
}
}
Sample output:
One,1
Two,2
Three,3
Four,4
I have list of object array (List<object[]> a) that come from different sources (files, sql, webservices) and I need a way to join them.
For example, I have this two list:
List<object[]> listA = new List<object[]>();
object[] a = new object[] { 1, "A", 1200, "2016-12-31" };
listA.Add(a);
a = new object[] { 2, "B", 5200, "2016-12-31" };
listA.Add(a);
a = new object[] { 3, "C", 3500, "2016-12-31" };
listA.Add(a);
a = new object[] { 4, "D", 100, "2016-12-31" };
listA.Add(a);
List<object[]> listB = new List<object[]>();
object[] b = new object[] { 44, 859, "2016-12-08" };
listB.Add(b);
b = new object[] { 23, 851, "2016-12-07" };
listB.Add(b);
b = new object[] { 31, 785, "2016-12-09" };
listB.Add(b);
And the result will be this one:
List<object[]> listC = new List<object[]>();
object[] c = new object[] { 1, "A", 1200+859, 44, "2016-12-08" };
listC.Add(c);
c = new object[] { 2, "B", 5200+851, 23, "2016-12-07" };
listC.Add(c);
c = new object[] { 3, "C", 3500+785, 31, "2016-12-09" };
listC.Add(c);
c = new object[] { 4, "D", 100, null, null };
listC.Add(c);
The lists are bigger than in the example and I have to configure how to merge then but if I found a way to do this in linq is the half of the way.
Any ideas?
You can zip both sequences and concat with left items from listA:
listA.Zip(listB, (a, b) =>
new object[] { a[0], a[1], (int)a[2] + (int)b[1], b[0], b[2] })
.Concat(listA.Skip(listB.Count).Select(a =>
new object[] { a[0], a[1], a[2], null, null }))
You can also use group join or select items from second list by index of item in first list.
I also suggest you to use custom classes instead of arrays of objects to make your code more readable, get nice type checking, descriptive properties, and intellisense. E.g.
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public int Value { get; set; }
public DateTime Date { get; set; }
}
And
public class Bar
{
public int Id { get; set; }
public int Value { get; set; }
public DateTime Date { get; set; }
}
Of course you should use more appropriate names here. Now your code will look like
List<Foo> foos = new List<Foo> {
new Foo { Id=1, Name="A", Value=1200, Date=new DateTime(2016,12,31) },
new Foo { Id=2, Name="B", Value=5200, Date=new DateTime(2016,12,31) },
new Foo { Id=3, Name="C", Value=3500, Date=new DateTime(2016,12,31) },
new Foo { Id=4, Name="D", Value=100, Date=new DateTime(2016,12,31) },
};
List<Bar> bars = new List<Bar> {
new Bar { Id=44, Value=859, Date=new DateTime(2016,12,8) },
new Bar { Id=23, Value=851, Date=new DateTime(2016,12,7) },
new Bar { Id=31, Value=785, Date=new DateTime(2016,12,9) }
};
You can also create custom type to hold combined data.
public class Result
{
public int FooId {get; set; }
public string Name {get; set; }
public int Value {get;set;}
public int? BarId {get;set;}
public DateTime? Date {get; set;}
}
And getting results will look like
var results = foos.Zip(bars, (f, b) => new Result{
FooId = f.Id, Name = f.Name, Value = f.Value + b.Value, BarId = b.Id, Date = b.Date
}).Concat(foos.Skip(bars.Count).Select(f => new Result {
FooId = f.Id, Name = f.Name, Value = f.Value
}));
Try Working Code
List table contains duplicating elements, how to improve this situation and copy data without duplicates in new list employee using linq?
For example output must be something like:
List<Employee> employee = new List<Employee>();
employee.Add(new Employee
{
Name = "Jhon",
components = new List<Component>
{
new Component { id = "4", work = "clear" },
new Component { id = "10", work = "load" },
new Component { id = "5", work = "convert"},
}
});
But how to do it using linq?
Code:
class Program
{
static void Main(string[] args)
{
List<Table> table = new List<Table>();
table.Add(new Table { Name = "Jhon", id = "4", work = "clear" });
table.Add(new Table { Name = "Jhon", id = "10", work = "load" });
table.Add(new Table { Name = "Jhon", id = "5", work = "convert" });
table.Add(new Table { Name = "Nick", id = "2", work = "load" });
table.Add(new Table { Name = "Nick", id = "7", work = "load" });
table.Add(new Table { Name = "Nick", id = "9", work = "load" });
}
}
public class Empoloyee
{
public string Name { get; set; }
public List<Component> components { get; set; }
}
public class Component
{
public string id { get; set; }
public string work { get; set; }
}
public class Table
{
public string Name { get; set; }
public string id { get; set; }
public string work { get; set; }
}
I guess you want have components grouped by employ name
List<Table> table = new List<Table>();
table.Add(new Table { Name = "Jhon", id = "4", work = "clear" });
table.Add(new Table { Name = "Jhon", id = "10", work = "load" });
table.Add(new Table { Name = "Jhon", id = "5", work = "convert" });
table.Add(new Table { Name = "Nick", id = "2", work = "load" });
table.Add(new Table { Name = "Nick", id = "7", work = "load" });
table.Add(new Table { Name = "Nick", id = "9", work = "load" });
var employee = table.GroupBy(t => t.Name)
.Select(g => new Empoloyee() {Name = g.Key, components = g.Select(t => new Component {id = t.id, work = t.work} ).ToList()})
.ToList();
This LINQ statement will generate the output you want:
List<Empoloyee> employee = table
.GroupBy(t => t.Name)
.Select(t => new Empoloyee() {
Name = t.Key,
components = t.Select(s => new Component() {
id = s.id,
work = s.work
})
.ToList()
})
.ToList();
What you need is Grouping on Name.
var results = table.GroupBy(t=>t.Name)
.Select( s=> new Empoloyee() {
Name = s.Key,
components= s.Select(c=> new Component() { id = c.id, work = c.work}).ToList()
}).ToList();
Working Code
What is the easiest and somewhat efficient way to convert a flat structure:
object[][] rawData = new object[][]
{
{ "A1", "B1", "C1" },
{ "A1", "B1", "C2" },
{ "A2", "B2", "C3" },
{ "A2", "B2", "C4" }
// .. more
};
into a hierarchical structure:
class X
{
public X ()
{
Cs = new List<string>();
}
public string A { get; set; }
public string B { get; set; }
public List<string> Cs { get; private set; }
}
the result should look like this
// pseudo code which describes structure:
result =
{
new X() { A = "A1", B = "B1", Cs = { "C1", "C2" } },
new X() { A = "A2", B = "B2", Cs = { "C3", "C4" } }
}
Preferably using Linq extension methods. Target class X could be changed (eg. a public setter for the List), only if not possible / useful as it is now.
for this particular case:
.GroupBy( x => new { a = x[0], b = x[1] } )
.Select( x => new { A = x.Key.a, B = x.Key.b, C = x.Select( c => c[2] ) })
Something like this should work if the depth of your hierarchy is limited (as in your example where you have only three levels A, B and C). I simplified your X a little bit:
class X {
public string A { get; set; }
public string B { get; set; }
public List<string> Cs { get; set; }
}
Then you can use nested GroupBy as many times as you need (depending on the depth of the hierarchy). It would be also relatively easy to rewrite this into a recursive method (that would work for arbitrarily deep hierarchies):
// Group by 'A'
rawData.GroupBy(aels => aels[0]).Select(a =>
// Group by 'B'
a.GroupBy(bels => bels[1]).Select(b =>
// Generate result of type 'X' for the current grouping
new X { A = a.Key, B = b.Key,
// Take the third element
Cs = b.Select(c => c[2]).ToList() }));
This is more explicit than the other solutions here, but maybe it will be more readable as it is more straightforward encoding of the idea...
With X members being strings and Cs being a private set, and rawData being an array of arrays of objects, I would add a constructor to X public X(string a, string b, List<string> cs) and then perform this code
var query = from row in rawData
group row by new { A = row[0], B = row[1] } into rowgroup
select new X((string)rowgroup.Key.A, (string)rowgroup.Key.B, rowgroup.Select(r => (string)r[2]).ToList());
This is on the following raw data
object[][] rawData = new object[][]
{
new object[] { "A1", "B1", "C1" },
new object[] { "A1", "B1", "C2" },
new object[] { "A2", "B2", "C3" },
new object[] { "A2", "B2", "C4" }
// .. more
};
I wanted to see if I could write this without anonymous instances. It's not too bad:
IEnumerable<X> myList =
from raw0 in rawData
group raw0 by raw0[0] into g0
let g1s =
(
from raw1 in g0
group raw1 by raw1[1]
)
from g1 in g1s
select new X()
{
A = g0.Key,
B = g1.Key,
C = g1.Select(raw2 => raw2[2]).ToList()
}