Filtering Nested array with linq - c#

I have an array like this coming from API response and I want to filter by nested property products to returns product with only id 11
"assets": [
{
"name": "abc",
"products": [
{
"id": "11",
"status": true
},
{
"id": "14",
"status": null
}
]
},
{
"name": "xyz",
"products": [
{
"id": "11",
"status": true
},
{
"id": "28",
"status": null
}
]
},
{
"name": "123",
"products": [
{
"id": "48",
"status": null
}
]
},
{
"name": "456",
"products": [
{
"id": "11",
"status": true
}
]
}
]
the resulting output should look like this,
"assets": [
{
"name": "abc",
"products": [
{
"id": "11",
"status": true
}
]
},
{
"name": "xyz",
"products": [
{
"id": "11",
"status": true
}
]
},
{
"name": "123",
"products": []
},
{
"name": "456",
"products": [
{
"id": "11",
"status": true
}
]
}
]
I'm trying to return filter output with the C# LINQ method. but, getting an error when filtering a nested array with the following method
"Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type"
assets.Select(asset => asset.products.Where(product => product.id == "11")).ToArray();

You can just remove all items from every products array, whose id doesn't equal 11. Parse JSON to JObject, iterate over assets array, find products with id different from 11 and remove them form original array
var json = JObject.Parse(jsonString);
foreach (var asset in json["assets"])
{
var productsArray = asset["products"] as JArray;
if (productsArray == null)
continue;
var productsToRemove = productsArray
.Where(o => o?["id"]?.Value<int>() != 11)
.ToList();
foreach (var product in productsToRemove)
productsArray.Remove(product);
}
Console.WriteLine(json);

Instead of Select and Applying a, Where try to remove the Products that you do not want.
Following is a sample code.
class Program
{
static void Main(string[] args)
{
var json = #"
{
'assets': [
{
'name': 'abc',
'products': [
{
'id': '11',
'status': true
},
{
'id': '14',
'status': null
}
]
},
{
'name': 'xyz',
'products': [
{
'id': '11',
'status': true
},
{
'id': '28',
'status': null
}
]
},
{
'name': '123',
'products': [
{
'id': '48',
'status': null
}
]
},
{
'name': '456',
'products': [
{
'id': '11',
'status': true
}
]
}
]}";
var root = JsonConvert.DeserializeObject<Root>(json);
var assets = root.Assets;
assets.ForEach(a =>
{
a.Products.RemoveAll(p => p.Id != 11);
});
}
}
public partial class Root
{
[JsonProperty("assets")]
public List<Asset> Assets { get; set; }
}
public partial class Asset
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("products")]
public List<Product> Products { get; set; }
}
public partial class Product
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("status")]
public bool? Status { get; set; }
}

To filter the list, you will need to create a new list with products whose ID == YourId. Following linq query does the necessary steps to create the list you want.
Filter out any assets that dont have any product with ID == 11. This is necessary to skip nulls in the new list that will be generated (Where statement)
Create a collection / list of new assets that only have the products whose ID == 11 (Select statement)
var list = assets.Where(x => x.Products.Where(y => y.Id.Equals("11")).Count() > 0)
.Select(asset => {
return new Asset() {
Name = asset.Name,
Products = asset.Products.Where(x => x.Id == "11").ToList()
};
}).ToList();
// Create the RootObject that holds a list of all the arrays if you want.
Rootobject newAssetCollection = new Rootobject() { Assets = list };
Below is the Json that was printed
Console.WriteLine(JsonConvert.SerializeObject(newAssetCollection, Formatting.Indented));
{
"assets": [
{
"name": "abc",
"products": [
{
"id": "11",
"status": true
}
]
},
{
"name": "xyz",
"products": [
{
"id": "11",
"status": true
}
]
},
{
"name": "456",
"products": [
{
"id": "11",
"status": true
}
]
}
]
}

Related

Dictionary<string, JToken> recursive search

I have DeserializeObject to a C# object however I have objects with dynamic object names so I have structured it like this:
public class RootObject
{
public string name { get; set; }
public TableLayout table{ get; set; }
}
public class TableLayout
{
public Attributes attributes { get; set; } //Static
public Info info { get; set; } //Static
[JsonExtensionData]
public Dictionary<string, JToken> item { get; set; }
}
So basically any dynamic objects that appear will be added to the dictionary and using JsonExtensionData will populate the rest of the property without creating the object classes. Here is my json:
string json = #"
{
"name": "Table 100",
"table": {
"attributes ": {
"id": "attributes",
"type": "attributes"
},
"info": {
"id": "info",
"type": "info"
},
"item-id12": {
"id": "item-id12",
"type": "Row"
"index": 0
},
"item-id16": {
"id": "item-id16",
"type": "Column"
"parentid": "item-id12"
},
"item-id21": {
"id": "item-id21",
"type": "Column",
"parentid": "item-id12"
}
}
}";
How can I use type ="row" and index value(increments to index 1 to evaluate next row) property to get all columns using parentId of column objects in my Dictionary.
Desired Output:
"item-id12": {
"id": "item-id12",
"type": "Row"
"index": 0
},
"item-id16": {
"id": "item-id16",
"type": "Column"
"parentid": "item-id12"
},
"item-id21": {
"id": "item-id21",
"type": "Column",
"parentid": "item-id12"
}
You can use linq to find your root object
var rootNode = json.table.item.Values
.FirstOrDefault(x => x["type"].Value<string>() == "Row" && x["index"].Value<int>() == 0);
if (rootNode == null)
return; // no such item
Now if this item exists use linq again and get all items from dictionary:
var childNodes = json.table.item.Values
.Where(x => x["parentid"]?.Value<string>() == rootNode["id"].Value<string>());
Next code
var output = new[] {rootNode}.Concat(childNodes);
foreach (var item in output)
Console.WriteLine(item);
will print
{
"id": "item-id12",
"type": "Row",
"index": 0
}
{
"id": "item-id16",
"type": "Column",
"parentid": "item-id12"
}
{
"id": "item-id21",
"type": "Column",
"parentid": "item-id12"
}
P.S. Your input json is invalid, it missing few commas

How do I sort a list based on its child object attributes?

I'm wondering if someone can elucidate a method to sort a list of objects based on a child object's attribute.
I'm working with the following model:
public class Content
{
public string Id { get; set; }
public List<ContentAttribute> Attributes { get; set; }
}
public class ContentAttribute
{
public string Value { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
Some sample data:
[
{
"Id": "123",
"Attributes": [
{
"Value": "abc",
"Id": "1a",
"Name": "name1"
},
{
"Value": "ghi",
"Id": "2b",
"Name": "name2"
}
]
},
{
"Id": "456",
"Attributes": [
{
"Value": "abc",
"Id": "1a",
"Name": "name2"
},
{
"Value": "def",
"Id": "2b",
"Name": "name3"
}
]
},
{
"Id": "789",
"Attributes": [
{
"Value": "abc",
"Id": "1a",
"Name": "name1"
},
{
"Value": "def",
"Id": "2b",
"Name": "name2"
}
]
}
]
How can I sort the Content objects by the Value of a specific attribute Name? For example, I would like to sort the above data by the Value of 'name2',
meaning the result would be
[
{"Id" : "456"},
{"Id" : "789"},
{"Id" : "123"}
]
Any help is greatly appreciated. (Using c#).
If Attributes always has an element with name name2 and you want an exception if it doesn't then:
var sorted = contents.OrderBy(c => c.Attributes.First(a => a.Name == "name2").Value).ToList();
Or if name2 could be missing and it's not deal breaker then use FirstOrDefault
var sorted = contents.OrderBy(c => c.Attributes.FirstOrDefault(a => a.Name == "name2")?.Value).ToList();

jsonResult with collectionname

Hi I would like to use the json collection from the code below in an angular repeater.
I need to give the collection a name but i dont know how
this is the code to generate the JSON
public JsonResult GetProducts()
{
var result = db.Products.ToList();
var list = JsonConvert.SerializeObject(result, Formatting.None, new JsonSerializerSettings(){ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore});
return Json(list,JsonRequestBehavior.AllowGet);
}
and this is the result
[{
"Category": {
"ID": 4,
"Name": "TEST"
},
"OrderDetails": [],
"ID": 10006,
"Description": "TEST",
"Name": "TEST",
"Price": 3.20,
"PictureUrl":"",
"CategoryId": 4,
"AddedToShop": "2016-12-11T14:52:57.677"
},
{
"Category": {
"ID": 4,
"Name": "TEST"
},
"OrderDetails": [],
"ID": 20005,
"Description": "TEST2",
"Name": "TEST2",
"Price": 3.20,
"PictureUrl":"",
"CategoryId": 4,
"AddedToShop": "2016-12-12T12:02:10.593"
}]
and I would like it to be like the code below so I can use the products tag to iterate .
{
"products": [{
"Category": {
"ID": 4,
"Name": "TEST"
},
"OrderDetails": [],
"ID": 10006,
"Description": "TEST",
"Name": "TEST",
"Price": 3.20,
"PictureUrl":"",
"CategoryId": 4,
"AddedToShop": "2016-12-11T14:52:57.677"
},
{
"Category": {
"ID": 4,
"Name": "TEST"
},
"OrderDetails": [],
"ID": 20005,
"Description": "TEST2",
"Name": "TEST2",
"Price": 3.20,
"PictureUrl":"",
"CategoryId": 4,
"AddedToShop": "2016-12-12T12:02:10.593"
}]}
If you are using WebAPI controllers you don't need to send JsonResult, all you need to do is create a class and send it back to client:
public class MyClass
{
public List<Product> Products { get; set; }
}
And in your controller:
public MyClass Get() {
return new MyClass {
Products = db.Products.ToList()
};
}
OR:
Simply create your object and then pass it in the serializer:
JsonConvert.SerializeObject( { "products": result }, Formatting.None, new JsonSerializerSettings(){ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore})
You can use
var list = JsonConvert.SerializeObject(new { products = result }, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore });
One solution for your problem is, define a seperate class and define a property for that class as either a collection or list of the type "db.Products"(Use the appropriate class name for this object as you have in your code) and when you serialize that object you will get it as you have asked for
class ProductList
{
public Collection<YourType> Products{get; set;}
}
OR
class ProductList
{
public List<YourType> Products{get; set;}
}

How to delete an Item from the JSON file using UniqueId of clicked item in ListView?

I've a JSON file like this:
{
"Groups": [
{
"UniqueId": "1",
"Name": "England",
"Members": [
{
"UniqueId": "Rooney",
"Name": "Rooney",
"JerseyNumber": "10",
"Position": "Forward"
},
{
"UniqueId": "Aquero",
"Name": "Aguero",
"JerseyNumber": "16",
"Position": "Forward"
},
{
"UniqueId": "Nani",
"Name": "Nani",
"JerseyNumber": "7",
"Position": "Midfielder"
}
]
}
]
}
I've been able to reach down to the Members array of JSON by this code:
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("Data2.json");
string jsonText = await FileIO.ReadTextAsync(file);
JsonObject jsonObject = JsonObject.Parse(jsonText);
JsonArray jsonArray = jsonObject["Groups"].GetArray()[0].GetObject()["Members"].GetArray();
I have the UniqueId of a Member and I want to search that member with UniqueId for its position within the "Members" array and then I want to delete that member. Suppose I've UniqueId="Nani", I want to search for that member with unique Id Nani and delete it.
I want the final result in JSON file as:
{
"Groups": [
{
"UniqueId": "1",
"Name": "England",
"Members": [
{
"UniqueId": "Rooney",
"Name": "Rooney",
"JerseyNumber": "10",
"Position": "Forward"
},
{
"UniqueId": "Aquero",
"Name": "Aguero",
"JerseyNumber": "16",
"Position": "Forward"
}
]
}
]
}
I think it will be better for you to create a class which matches your json tree. I am using .net 3.5 so i think i miss dll for json class you are using. But you will get the logic in this code below, comments will help you too
public class Groups // "Groups": [
{
public int UniqueId { get; set; } // "UniqueId": "1",
public String Name { get; set; } // "Name": "England",
public List<Member> ListMembers { get; set; } // "Members": [
public Groups(string json)
{
/* use your json object to get different data */
UniqueId = "Group UniqueId";
Name = "Group Name";
// get all member
foreach (jsonMember in jsonObject.Members)
{
Member member = new Member
{
UniqueId = "jsonMember UniqueId",
Name = "jsonMember Name",
JerseyNumber = "jsonMember JerseyNumber",
Position = "jsonMember Position",
};
ListMembers.Add(member);
}
}
public class Member // {"UniqueId":"Nani", "Name":"Nani", ... }
{
public string UniqueId { get; set; } // "UniqueId": "Aquero",
public String Name { get; set; } // "Name": "Aguero",
public int JerseyNumber { get; set; } // "JerseyNumber": "16",
public string Position { get; set; } // "Position": "Forward"
}
public void Delete(string UniqueId) // by example Delete("Nani")
{
ListMembers.RemoveAll(m => m.UniqueId == UniqueId);
}
}

Generate c# classes from json dynamically

I usually use json2csharp to generate json classes to c#. But I do have problem. My json is have dynamic depth like this
{
"kategori": [
{
"id": "1",
"namakategori": "Tips & Trick",
"parent_id": "0",
"children": [
{
"id": "348",
"namakategori": "Fotografi",
"parent_id": "1",
"children": []
},
{
"id": "370",
"namakategori": "Hacking",
"parent_id": "1",
"children": []
}
]
},
{
"id": "12",
"namakategori": "Aplikasi",
"parent_id": "0",
"children": [
{
"id": "13",
"namakategori": "Tools",
"parent_id": "12",
"children": [
{
"id": "14",
"namakategori": "Toolsorder",
"parent_id": "13",
"children":[]
},
]
},
]
},
]
}
So how do I generate json classes dynamically so it can be used for my json? In above example I have 3 depth. But if I go to different page maybe it have 4 or more depth.
You don't need to declere your classes dynamically. This should work:
public class Child
{
public string id { get; set; }
public string namakategori { get; set; }
public string parent_id { get; set; }
public List<Child> children { get; set; } // <-- See this
}
public class RootObj
{
public List<Child> kategori { set; get; }
}
To deserialize I'll use Json.Net
var res = JsonConvert.DeserializeObject<RootObj>(json);
You can always use the Newtonsoft.Json
For Instance,
JObject result = (JObject) JsonConvert.DeserializeObject(yourJsonDataHere);
var katObject = result.Property("kategori").Value;
and so on...
PS: Not sure if Newtonsoft.Json is supported on WP7.

Categories