How to put lists together into json in C#? - c#

I have this code here in C# (just a sample):
var list1 = ( from x
join y
select new
{
id, name
});
var counta = list1.count;
if (counta > 0)
{
for (var i = 0; i < counta; i++)
{
var userid = list1[i].id;
var user = user.Where(a => a.id == user).Select(a => a.userid).FirstOrDefault();
var list2 = (
from f
join g.Where(a => a.userid = user)select new
{
hourId, hourName
}
);
if (list2 > 0)
{
foreach (var product in list2)
{
var list3 = (
from p.
where (a => a.id == user)join q.
where (a => a.id == user)select new
{
productId, productName
});
}
}
}
}
Here is list1,list2,list3 relationship: list1 has many list2, list2 has many list3 and here is the JSON that I expected to return:
[
{
"list1": {
"id": 1,
"name": "Adam",
"list2": [
{
"hourId": 1,
"hourName": "08:00",
"list3": [
{
"productId": 1,
"productName": "Candy"
},
{
"productId": 2,
"productName": "Cookie"
}
]
},
{
"hourId": 2,
"hourName": "09:00",
"list3": [
{
"productId": 1,
"productName": "Candy"
},
{
"productId": 2,
"productName": "Cookie"
}
]
}
]
}
}
]
So my question here is how can I put list1, list2, list3 together to return the below JSON? Do I have to join 3 lists in LINQ again?
Thank you!

Related

Left Outer Join with multiple Data tables

I have 3 DataTables
DataTable1
Id Version URL Owner
1 1 "xx" "alice"
2 1 "yy" "bob"
3 1 "zz" "Mike"
4 1 "ww" "Rob"
5 1 "ww" "Bick"
DataTable2
Id Version DomainID Region Type
1 1 aa asia 1
2 1 bb europe 2
3 1 cc africa 1
4 1 dd aus1 0
DataTable3
Id Size FreeSpace
aa 2500 2000
bb 3300 3000
cc 5500 50
Expected Join
Id Version URL Owner DomainID Region Type Size Freespace
1 1 "xx" "alice" aa asia 1 2500 2000
2 1 "yy" "bob" bb europe 2 3300 3000
3 1 "zz" "Mike" cc africa 1 5500 50
4 1 "ww" "sean" dd aus1 0 null null
5 1 "ww" "Bick" null null null null null
I am doing a Join Operation on these tables using Linq as follows:
// Datatable1 joins with Datatable2 on Id and version (datatable1) --> Id and version (datatable2)
// Datatable2 joins with Datatable3 on DomainId(datatable2) --> Id(datatable3)
var result = from dataRows1 in DataTable1.AsEnumerable()
join dataRows2 in DataTable2.AsEnumerable() on
new
{
Id = dataRows1.Field<long>("Id"),
Version = dataRows1.Field<long>("version")
} equals new
{
Id = dataRows2.Field<long>("Id"),
Version = dataRows2.Field<long>("version")
}
into tempJoin
from datarowc in tempJoin.DefaultIfEmpty()
join dataRows3 in DataTable3.AsEnumerable() on
dataRowsc.Field<long>("DomainId") equals dataRows3.Field<long>("Id")
select new
{
datarow1,
datarowc,
datarow3
}
I am getting an exception of datarowc to be null.
Not quite sure why datarowc is null here and how to achieve the expected join.
using System.Data;
using System.Linq;
namespace CodeWars
{
class Program
{
static void Main(string[] args)
{
var result = datarows1.AsEnumerable()
.Select(x => new
{
Tab1Row = x,
Tab2Row = datarows2.AsEnumerable().FirstOrDefault(
y => x.Field<int>("Id") == y.Field<int>("Id") &&
x.Field<int>("Version") == y.Field<int>("Version")
)
}
)
.Select(x => new
{
Tab1Row = x.Tab1Row,
Tab2Row = x.Tab2Row,
Tab3Row = datarows3.AsEnumerable().FirstOrDefault(
y => x?.Tab2Row?.Field<string>("DomainId") == y.Field<string>("Id")
)
}
);
}
static DataTable datarows1 = new DataTable
{
Columns = {
{ "Id", typeof(int) },
{ "Version", typeof(int) },
{ "URL", typeof(string) },
{ "Owner", typeof(string) },
},
Rows = {
{ 1, 1, "xx", "alice" },
{ 2, 1, "yy", "bob" },
{ 3, 1, "vv", "mike" },
{ 4, 1, "ww", "rob" },
{ 5, 1, "zz", "bick" },
}
};
static DataTable datarows2 = new DataTable
{
Columns = {
{ "Id", typeof(int) },
{ "Version", typeof(int) },
{ "DomainID", typeof(string) },
{ "Region", typeof(string) },
{ "Type", typeof(int) },
},
Rows = {
{ 1, 1, "aa", "asia", 1 },
{ 2, 1, "bb", "europe", 2},
{ 3, 1, "cc", "asia", 1},
{ 4, 1, "dd", "aus1", 0},
}
};
static DataTable datarows3 = new DataTable
{
Columns = {
{ "Id", typeof(string) },
{ "Size", typeof(int) },
{ "FreeSpace", typeof(int) },
},
Rows = {
{ "aa", 2500, 2000 },
{ "bb", 3300, 3000 },
{ "cc",5500, 50},
}
};
}
}
.Join() performs inner join, but you want left outer join, so forget about .Join()
Code I've provided gives you the result you expect. But maybe you need to add one more Select to form datastructure you need.

Why OrderBy does not sort the data?

I want to group and sort data, but OrderBy function is not working as it should, and I'm wondering what I'm doing wrong
Code:
var data = new List<PreparedData>() {
new PreparedData {
IsGroup = false,
Service = "Number 5",
Name = "Banana",
SomeValue = 5,
},
new PreparedData {
IsGroup = false,
Service = "Number 5",
Name = "Apple",
SomeValue = 5,
},
new PreparedData {
IsGroup = false,
Service = "Number 3",
Name = "Apple",
SomeValue = 5,
},
new PreparedData {
IsGroup = false,
Service = "Number 3",
Name = "Blueberry",
SomeValue = 9,
},
new PreparedData {
IsGroup = true,
Service = "Number 9",
Name = "Garlic",
SomeValue = 7,
}
}
var groupedAndSortedData = data.GroupBy(x => x.IsGroup).Select(isGroup => new FruitViewData
{
IsGroup = isGroup.Key,
FruitData = isGroup.GroupBy(s => s.Service).Select(service => new FruitServiceData
{
Service = service.OrderBy(z => z.Service).First().Service,
FruitTypeData = service.OrderBy(x => x.Name).Select(fruitType => new FruitTypeData
{
Name = fruitType.Name,
SomeValue = fruitType.SomeValue
}
}
}
At the end I get:
[
{
IsGroup: false
FruitData: [
{
Service: "Number 5",
FruitTypeData: [
{
Name: "Banana",
SomeValue = 5,
},
{
Name: "Apple",
SomeValue = 5,
},
]
},
{
Service: "Number 3",
FruitTypeData: [
{
Name: "Apple",
SomeValue = 5,
},
{
Name: "Blueberry",
SomeValue = 9,
},
]
]
},
{
IsGroup: true
FruitData: [
{
Service: "Number 9",
FruitTypeData: [
{
Name: "Garlic",
SomeValue = 9,
}
]
},
]
},
]
But I would like to get sorted data like:
[
{
IsGroup: false
FruitData: [
{
Service: "Number 3",
FruitTypeData: [
{
Name: "Apple",
SomeValue = 5,
},
{
Name: "Blueberry",
SomeValue = 9,
},
]
},
{
Service: "Number 5",
FruitTypeData: [
{
Name: "Apple",
SomeValue = 5,
},
{
Name: "Banana",
SomeValue = 5,
},
]
},
]
},
{
IsGroup: true
FruitData: [
{
Service: "Number 9",
FruitTypeData: [
{
Name: "Garlic",
SomeValue = 9,
}
]
},
]
},
]
I tried to sort it in a different way like for example using the foreach loop after groupedAndSortedData and add OrderBy function to every iteration but also without satisfactory effect
What should I change to get the expected result?
It looks to me like you need to order the FruitData results:
var groupedAndSortedData = data.GroupBy(x => x.IsGroup).Select(isGroup => new FruitViewData
{
IsGroup = isGroup.Key,
FruitData = isGroup.GroupBy(s => s.Service).Select(service => new FruitServiceData
{
Service = service.OrderBy(z => z.Service).First().Service,
FruitTypeData = service.OrderBy(x => x.Name).Select(fruitType => new FruitTypeData
{
Name = fruitType.Name,
SomeValue = fruitType.SomeValue
})
}).OrderBy(fd => fd.Service) //This here
});
Notice the .OrderBy(fd => fd.Service) method call.

How make a LINQ Select, GroupBy and Count from a List of Lists?

I have a List<IEnumerable<Foo>>
This makes an list like this:
{
[
{a: 1, b: 2},
{a: 1, b: 3}
],
[{a: 1, b: 2}]
}
And i need to arrange it in this way, grouping the objects by the a and b values. I was no able to make a group query to anything like the example below.
{
{a: 1, b: 2, count: 2},
{a: 1, b: 3, count: 1}
}
Edit:
Here's the code that i have and the output:
var list = new List<object>();
foreach (var f in fooList)
{
var x = from y in f
group y by new { y.a, y.b } into z
select new
{
Foo = z.Key,
Count = z.Count()
};
a.Add(x);
}
Output:
[
{
"Foo": {
"a": 1,
"b": 2
},
"count": 1
},
{
"Foo": {
"a": 1,
"b": 2
},
"count": 1
},
{
"Foo": {
"a": 1,
"b": 3
},
"count": 1
}
],
Something like this will work:
var list = new List<List<Foo>>();
list.Add(new List<Foo> {new Foo {A = 1, B = 2}, new Foo {A = 1, B = 3}});
list.Add(new List<Foo> {new Foo {A = 1, B = 2}});
var result = list.SelectMany(l => l)
.GroupBy(l => new {l.A, l.B})
.Select(grp => new {A = grp.Key.A, B = grp.Key.B, Count = grp.Count()});
First the list gets flattened with SelectMany(). After that we GroupBy multiple values by using an anonymous object. After grouping we are selecting the initial values and the count out of the grouping into an anonymous object.
It seems like you want your result to be serialized. Using Json.Net, this will be the output:
[
{
"A":1,
"B":2,
"Count":2
},
{
"A":1,
"B":3,
"Count":1
}
]
You have to flatten your first list, as the nested level is irrelevant to your desired result. This shows how to flatten. I think your GroupBy is correct.
List<List<Foo>> list = new List<List<Foo>>();
list.Add(new List<Foo>());
list[0].Add(new Foo { a = 1, b = 2 });
list[0].Add(new Foo { a = 1, b = 3 });
var subList = new List<Foo>();
subList.Add(new Foo { a = 1, b = 2 });
list.Add(subList);
var flat = list.SelectMany(i => i);
var grouped = from foo in flat group foo by new { foo.a, foo.b } into g select g;
Assert.AreEqual(true, grouped.First().Count() == 2);
Assert.AreEqual(true, grouped.Last().Count() == 1);

C# Web API PUTmethod for Json Multiple Array

I am trying to code a PUT method for a multiple array but I am getting a NULL error.
this is my code inside my controller for valuestory where its child later is Area of Interest and AOI Value Driver:
// PUT: api/ValueStories/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutValueStory(int id, ValueStory valueStory)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != valueStory.Id)
{
return BadRequest();
}
//To update Value Story Item all the way to
//Area of interest and child layers
var vsid = id;
var vs = (from v in db.ValueStories where v.Id == vsid select v).FirstOrDefault();
//db.Entry(valueStory).State = EntityState.Modified;
if (vs == null)
{
return NotFound();
}
else
{
vs.Id = vsid;
vs.ModifiedDate = DateTime.Now;
//AreaOfInterest and AOIValueDriver START
foreach (var item in vs.AreaOfInterest)
{
var aoi = (from a in db.AreaOfInterests where a.Id == vs.Id select a).FirstOrDefault();
if (aoi != null)
{
aoi.AOIName = item.AOIName;
aoi.Selected = item.Selected;
aoi.Id = vs.Id;
//AOIValueDriver START
foreach (var item2 in aoi.AOIValueDrivers)
{
var aoivd = (from b in db.AOIValueDrivers where b.AOIId == aoi.AOIId select b).FirstOrDefault();
if (aoivd != null)
{
aoivd.Item = item2.Item;
aoivd.SubItem = item2.SubItem;
aoivd.Value = item2.Value;
}
}
//AOIValueDriver EMD
}
}
//AreaOfInterest and AOIValueDriver END
// --------------------------------//
}
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ValueStoryExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
and this is the json parameter that I am trying to pass:
{
"Id": 1,
"ValueStoryName": "Value Story 101",
"Organization": "Charity Foundation",
"Industry": "Education",
"Currency": "$ ",
"AnnualRevenue": 1000,
"AreaOfInterest": [
{
"Id": 1,
"AOIId": 1,
"AOIName": "Supply Chain/ Direct Materials",
"Selected": false,
"AOIValueDrivers": [
{
"AOIId": 1,
"AOIVDId": 1,
"Item": "Negotiate better prices & conditions",
"SubItem": "Automate the process of sourcing of direct materials and integrate it to you ERP and key execution systems",
"Value": 0
}
]
},
{
"Id": 1,
"AOIId": 2,
"AOIName": "Sourcing",
"Selected": true,
"AOIValueDrivers": [
{
"AOIId": 2,
"AOIVDId": 10,
"Item": "Negotiate better prices & conditions",
"SubItem": "Foster supplier competition to reduce pricing and obtain best market value",
"Value": 3
}
]
},
{
"Id": 1,
"AOIId": 3,
"AOIName": "Procurement",
"Selected": true,
"AOIValueDrivers": [
{
"AOIId": 3,
"AOIVDId": 23,
"Item": "Lower costs",
"SubItem": "Provide access to an electronic marketplace of pre-sourced goods and services",
"Value": 3
}
]
},
{
"Id": 1,
"AOIId": 4,
"AOIName": "Accounts Payable",
"Selected": true,
"AOIValueDrivers": [
{
"AOIId": 4,
"AOIVDId": 32,
"Item": "Lower costs",
"SubItem": "Pay on time",
"Value": 3
}
]
},
{
"Id": 1,
"AOIId": 5,
"AOIName": "Working Captila/ Treasury",
"Selected": true,
"AOIValueDrivers": [
{
"AOIId": 5,
"AOIVDId": 37,
"Item": "Free up working capital",
"SubItem": "Capture more early pay discounts and allow suppliers to dynamically select discount rate and payment terms",
"Value": 3
}
]
},
{
"Id": 1,
"AOIId": 6,
"AOIName": "Risk and Compliance",
"Selected": false,
"AOIValueDrivers": [
{
"AOIId": 6,
"AOIVDId": 42,
"Item": "Protect your revenue",
"SubItem": "Proactively monitor and predict supply risks in real time",
"Value": 3
}
]
}
]
}
and the error that I am getting from postman is here
https://ibb.co/jMHmuv
I can't fully understand what does the error mean but I hope that somebody can help me with this.
revised controller code for the PUT method:
// PUT: api/ValueStories/5
[ResponseType(typeof(void))]
public async Task<IHttpActionResult> PutValueStory(int id, ValueStory valueStory)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != valueStory.Id)
{
return BadRequest();
}
//To update Value Story Item all the way to
//Area of interest and child layers
//Business value to you and child layers
//Business value from SAP and child layers
var vs = (from v in db.ValueStories where v.Id.Equals(id) select v).FirstOrDefault();
//db.Entry(valueStory).State = EntityState.Modified;
if (vs != null)
{
vs.ModifiedDate = DateTime.Now;
vs.ValueStoryName = valueStory.ValueStoryName;
vs.Organization = valueStory.Organization;
vs.Location = valueStory.Location;
vs.Industry = valueStory.Industry;
vs.Currency = valueStory.Currency;
vs.AnnualRevenue = valueStory.AnnualRevenue;
vs.MutualActionPlan = valueStory.MutualActionPlan;
vs.Id = valueStory.Id;
}
else
{
return NotFound();
}
//areaofinterest and aoivaluedriver start
foreach (var item in valueStory.AreaOfInterest)
{
var aoi = (from a in db.AreaOfInterests where a.Id == vs.Id select a).FirstOrDefault();
if (aoi != null)
{
aoi.Selected = item.Selected;
aoi.Id = vs.Id;
//aoi.AOIId = aoi.AOIId;
//aoivaluedriver start
foreach (var item2 in item.AOIValueDrivers)
{
var aoivd = (from b in db.AOIValueDrivers where b.AOIId == aoi.AOIId select b).FirstOrDefault();
if (aoivd != null)
{
aoivd.Value = item2.Value;
aoivd.AOIId = aoi.AOIId;
//aoivd.AOIVDId = aoivd.AOIVDId;
}
}
//aoivaluedriver emd
}
}
//areaofinterest and aoivaluedriver end
// --------------------------------//
//}
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ValueStoryExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
revised Json input:
{
"Id": 1,
"ValueStoryName": "Value Story 222",
"Organization": "ABC",
"Industry": 11,
"Location": "Singapore",
"Currency": "P",
"AnnualRevenue":212000,
"MutualActionPlan": "testing789",
"AreaOfInterest": [
{
"AOIId": 1,
"Selected": false,
"AOIValueDrivers": [
{
"AOIVDId": 1,
"Value": 1
},
{
"AOIVDId": 2,
"Value": 2
},
{
"AOIVDId": 3,
"Value": 1
},
{
"AOIVDId": 4,
"Value": 1
},
{
"AOIVDId": 5,
"Value": 1
},
{
"AOIVDId": 6,
"Value": 5
},
{
"AOIVDId": 7,
"Value": 1
},
{
"AOIVDId": 8,
"Value": 1
},
{
"AOIVDId": 9,
"Value": 3
}
]
}
]
}
I managed to get it working by putting additonal condition to my query for aoi and aoivd
//areaofinterest and aoivaluedriver START
foreach (var item in valueStory.AreaOfInterest)
{
var aoi = (from a in db.AreaOfInterests where a.Id == item.Id && a.AOIId == item.AOIId select a).FirstOrDefault();
if (aoi != null)
{
aoi.Selected = item.Selected;
//aoivaluedriver START
foreach (var item2 in item.AOIValueDrivers)
{
var aoivd = (from b in db.AOIValueDrivers where b.AOIId == item2.AOIId && b.AOIVDId == item2.AOIVDId select b).FirstOrDefault();
if (aoivd != null)
{
aoivd.Value = item2.Value;
}
}
//aoivaluedriver END
}
}
//areaofinterest and aoivaluedriver END

How to separate a collection into different "buckets"

I have a collection of C# objects. Each object has, for data members, a string which is a guid, an index which is an int, and a string which is a document name. Here is what a typical collection looks like:
"guid1","c:\temp\doc1.docx",1
"guid1","c:\temp\doc2.docx",2
"guid1","c:\temp\doc3.docx",3
"guid1","c:\temp\doc4.docx",4
"guid2","c:\temp\doc5.docx",5
"guid1","c:\temp\doc6.docx",6
"guid1","c:\temp\doc7.docx",7
I need to end up breaking the collection into individual collections like this:
"guid1","c:\temp\doc1.docx",1
"guid1","c:\temp\doc2.docx",2
"guid1","c:\temp\doc3.docx",3
"guid1","c:\temp\doc4.docx",4
"guid2","c:\temp\doc5.docx",5
"guid1","c:\temp\doc6.docx",6
"guid1","c:\temp\doc7.docx",7
These individual collections will then be fed into another function for processing. Trying to figure out the best way to do this.
Try using Linq, GroupBy:
IEnumerable<MyClass> source = ...;
int group = 0;
Guid key = new Guid();
// Let's have an array of arrays (array of individual collections) as a result
MyClass[][] buckets = source
.GroupBy(item => {
if (group == 0 || key != item.guid) {
key = item.guid;
group += 1;
}
return group; })
.Select(chunk => chunk.ToArray())
.ToArray();
I did this with linq and no external variables
var list = new []{
new {Id = "guid1", Path = #"c:\temp\doc1.docx", Index = 1},
new {Id = "guid1", Path = #"c:\temp\doc2.docx", Index = 2},
new {Id = "guid1", Path = #"c:\temp\doc3.docx", Index = 3},
new {Id = "guid1", Path = #"c:\temp\doc4.docx", Index = 4},
new {Id = "guid2", Path = #"c:\temp\doc5.docx", Index = 5},
new {Id = "guid1", Path = #"c:\temp\doc6.docx", Index = 6},
new {Id = "guid1", Path = #"c:\temp\doc7.docx", Index = 7}
};
var batchSize = 3;
var batched = list.GroupBy(x => x.Id)
.Select(x => x.GroupBy(p => p.Index/batchSize)
.ToArray());
string json = JsonConvert.SerializeObject(batched);
Console.WriteLine(json);
The json serialization is just for printing to the screen the output, which would be:
[
[
[
{
"Id":"guid1",
"Path":"c:\\temp\\doc1.docx",
"Index":1
},
{
"Id":"guid1",
"Path":"c:\\temp\\doc2.docx",
"Index":2
}
],
[
{
"Id":"guid1",
"Path":"c:\\temp\\doc3.docx",
"Index":3
},
{
"Id":"guid1",
"Path":"c:\\temp\\doc4.docx",
"Index":4
}
],
[
{
"Id":"guid1",
"Path":"c:\\temp\\doc6.docx",
"Index":6
},
{
"Id":"guid1",
"Path":"c:\\temp\\doc7.docx",
"Index":7
}
]
],
[
[
{
"Id":"guid2",
"Path":"c:\\temp\\doc5.docx",
"Index":5
}
]
]
]

Categories

Resources