I have a c# class that looks something like this:
public class Item
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Type { get; set; }
}
and i would like to convert it to json where json property name is item name and its value is item description. if some item has any children then i would like the json property name to stay as item name and the children to be added like item name:item description(the parent item description and type become empty string if it has any children, except when the type is array). The type has following values: array, string, int, object. if the item type is an array then each time a child is added to the type array item, the child is item description. so i would like those values to be added to the json array as well.
if the type is string or int the json property value should be int or string.
I am trying to write custom JsonSerializer but i am getting nowhere.
so if i have a list with items:
List<Item> MyItems = new List<Item>()
{
new Item { Id = 1, ParentId = null, Name = "Name1", Description = "", Type = "" },
new Item { Id = 2, ParentId = 1, Name = "Name2", Description = "Description1", Type = "String" },
new Item { Id = 3, ParentId = 1, Name = "Name3", Description = "", Type = "Array" },
new Item { Id = 4, ParentId = 3, Name = "", Description = "ArrayItem1", Type = "" },
new Item { Id = 5, ParentId = 3, Name = "", Description = "ArrayItem2", Type = "" },
new Item { Id = 6, ParentId = 3, Name = "", Description = "ArrayItem3", Type = "" },
new Item { Id = 7, ParentId = null, Name = "Name4", Description = "5", Type = "Int" },
};
then the json should like this:
{
"name1":{
"name2":"description1",
"name3":[
"ArrayItem1",
"ArrayItem2",
"ArrayItem1"
]
},
"name4":5
}
Here's an extension method that I think does what you want:
public static class Ex
{
public static string ToJson(this List<Item> items)
{
var lookup = items.ToLookup(x => x.ParentId);
JObject ToJson(int? parentId)
{
JProperty ToProperty(Item item)
{
switch (item.Type)
{
case "":
return new JProperty(item.Name, ToJson(item.Id));
case "String":
return new JProperty(item.Name, item.Description);
case "Array":
return new JProperty(item.Name, lookup[item.Id].Select(x => x.Description).ToArray());
case "Int":
return new JProperty(item.Name, int.Parse(item.Description));
default:
return new JProperty(item.Name);
}
}
return new JObject(lookup[parentId].Select(x => ToProperty(x)));
}
var output = ToJson(null);
var text = Newtonsoft.Json.JsonConvert.SerializeObject(output, Newtonsoft.Json.Formatting.Indented);
return text;
}
}
I run it like this:
List<Item> MyItems = new List<Item>()
{
new Item { Id = 1, ParentId = null, Name = "Name1", Description = "", Type = "" },
new Item { Id = 2, ParentId = 1, Name = "Name2", Description = "Description1", Type = "String" },
new Item { Id = 3, ParentId = 1, Name = "Name3", Description = "", Type = "Array" },
new Item { Id = 4, ParentId = 3, Name = "", Description = "ArrayItem1", Type = "" },
new Item { Id = 5, ParentId = 3, Name = "", Description = "ArrayItem2", Type = "" },
new Item { Id = 6, ParentId = 3, Name = "", Description = "ArrayItem3", Type = "" },
new Item { Id = 7, ParentId = null, Name = "Name4", Description = "5", Type = "Int" },
};
Console.WriteLine(MyItems.ToJson());
And I get this out:
{
"Name1": {
"Name2": "Description1",
"Name3": [
"ArrayItem1",
"ArrayItem2",
"ArrayItem3"
]
},
"Name4": 5
}
Related
There are all view locations (let's say 100, these are locations for the TreeView):
Id, Name, ParentId
1 Root Null
2 Semi-root 1
3 Semi-semi-root 2
4 ..... ....
And there is data in which we received only those locations that correspond to our values from another request:
Id, Name, ParentId
22 Location1 12
36 Location38 21
99 Location38 3
Need to get all parent hierarchy for data which we get from request.
There is the class:
public class TreeViewNode {
public Guid Id {get; set;}
public string Name {get; set;}
public Guid ParentId {get; set;}
}
Test data:
private IEnumerable<TreeViewNode> SeedData()
{
return new List<TreeViewNode>
{
new()
{
Id = 1,
Name = "Root",
ParentId = null
},
new()
{
Id = 2,
Name = "Semi-root",
ParentId = 1
},
new()
{
Id = 3,
Name = "Semi te",
ParentId = 2
},
new()
{
Id = 4,
Name = "Semi oi",
ParentId = 2
},
new()
{
Id = 5,
Name = "Child",
ParentId = 3
},
new()
{
Id = 6,
Name = "Child 1",
ParentId = 4
},
new()
{
Id = 7,
Name = "Child 2",
ParentId = 1
},
new()
{
Id = 8,
Name = "Child 3",
ParentId = 1
},
new()
{
Id = 9,
Name = "Child 4",
ParentId = 1
},
new()
{
Id = 10,
Name = "Child 6",
ParentId = 2
}
};
}
Example data got from request:
var dataFromRequest = new List<TreeViewNode>
{
new()
{
Id = 8,
Name = "Child 3",
ParentId = 1
},
new()
{
Id = 10,
Name = "Child 6",
ParentId = 2
},
new()
{
Id = 33,
Name = "Child",
ParentId = 3
},
new()
{
Id = 4,
Name = "Semi oi",
ParentId = 2
}
};
And as result need to get list of parents like this:
Id Name ParentId
1 Root Null
2 Semi-root 1
3 Semi te 2
And here can be 5 or more levels of parents
Something like this
// create Dictionary for lookups
var lookup = dataFromRequest.ToDictionary(x => x.Id.Value, x => x);
var lookFor = new TreeViewNode()
{
Id = 6,
Name = "Child 1",
ParentId = 4
};
// get all the parents
GetParents(lookup, lookFor);
Helper method to get all parents
private void GetParents(Dictionary<int, TreeViewNode> lookup,
TreeViewNode lookFor)
{
while (lookFor != null)
{
// Alternative: Add lookFor to List<TreeViewNode> here and return at
// the end of the method
Debug.WriteLine($"{lookFor.Id} {lookFor.Name} {lookFor.ParentId}");
if (lookFor.ParentId == null)
break;
// cast ParentId to corrent dataType here Guid or int
lookup.TryGetValue((int)lookFor.ParentId, out var parentNode);
lookFor = parentNode;
}
}
Remember to keep your lookup Dict up to date when you get more IEnumerable<TreeViewNode>
Another thing you could do is set the parent node inside the TreeViewNode like this:
public class TreeViewNode {
...
// set ParentNode by lookup in the Dictionary once
public TreeViewNode ParentNode {get; set;}
}
I have a data definition
I Deserialize JSON to this object
#return is JSON
JsonConvert.DeserializeObject<List<Dictionary<Object, Object>>>(utils.RemoveJsonOuterClass("GetTable", JsonConvert.DeserializeObject(#return).ToString()));
olist = [
[{
"item": 1
"Name "One"
}],
[{
"item": 2
"Name "Two"
}],
[{
"item": 1
"Name "One Two"
}]
];
This is a List<Dictionary<Object, Object>>
I need to find all of the items where "item" == 1.
Can I Use Linq? or is there any other way while using a large amount of data?
First: Your json is not correct fix that.
A colon should be present between Name and value.
A comma should be present after item value
and then change your code as below
//Create a class matching response object
public class ResponseItem
{
[JsonProperty("item")]
public int Item { get; set; }
public string Name { get; set; }
}
var responseJson = utils.RemoveJsonOuterClass("GetTable",
JsonConvert.DeserializeObject(#return).ToString();
var responseData = Newtonsoft.Json.JsonConvert.DeserializeObject<List<List<ResponseItem, ResponseItem>>>(responseJson);
Then use foreach with Where and apply condition
foreach (var responseObject in responseData.Where(x=>x.First().Item.Equals(1)))
{
}
Where is deferred execution and on each loop, it returns an object.
Here is the screenshot of my local execution.
Don't know if u're right with the object type. But the task is easy to solve:
static void Main(string[] args)
{
// Build the object
List<Dictionary<int, TestObject>> list = new List<Dictionary<int, TestObject>>();
// fill it with dictionaries
list.Add(new List<TestObject>()
{
new TestObject(){ Id = 1, Name = "One" },
new TestObject() { Id = 2, Name = "Two" },
new TestObject() { Id = 3, Name = "Three" }
}.ToDictionary(d => d.Id));
list.Add(new List<TestObject>()
{
new TestObject() { Id = 2, Name = "Two" },
new TestObject() { Id = 3, Name = "Three" }
}.ToDictionary(d => d.Id));
list.Add(new List<TestObject>()
{
new TestObject(){ Id = 1, Name = "One" },
new TestObject() { Id = 2, Name = "Two" }
}.ToDictionary(d => d.Id));
// Let's build a single list to work with
IEnumerable<TestObject> completeList = list.SelectMany(s => s.Values);
// aaaand filter it
IEnumerable<TestObject> filteredList = completeList.Where(l => l.Id == 1);
}
public class TestObject
{
public int Id { get; set; }
public string Name { get; set; }
}
Most part is initialization ;-)
I have the following class
public class Item
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Content { get; set; }
public bool IsLastItem { get; set; }
}
Let say I have the following model and I want to remove items which IsLastItem = false and don't have child. In this scenario item4 and item7 should remove from list.
I get the list of my model from database and I simulated it in the code block like this
var items = new List<Item>
{
new Item
{
Id = 1,
ParentId = 0,
Content = "item1",
IsLastItem = false
},
new Item
{
Id = 2,
ParentId = 1,
Content = "item2",
IsLastItem = false
},
new Item
{
Id = 3,
ParentId = 1,
Content = "item3",
IsLastItem = true
},
new Item
{
Id = 4,
ParentId = 1,
Content = "item4",
IsLastItem = false
},
new Item
{
Id = 5,
ParentId = 2,
Content = "item5",
IsLastItem = false
},
new Item
{
Id = 6,
ParentId = 5,
Content = "item6",
IsLastItem = false
},
new Item
{
Id = 7,
ParentId = 5,
Content = "item7",
IsLastItem = false
},
new Item
{
Id = 8,
ParentId = 6,
Content = "item8",
IsLastItem = true
},
new Item
{
Id = 9,
ParentId = 8,
Content = "item9",
IsLastItem = true
}
};
A flat list like this is not optimal for these kinds of operations - it might be nice if you could get the list back in some kind of tree structure (maybe return it from SQL using FOR XML or JSON if you're on 2016) to begin with, where you'd have an easier time traversing the tree.
Also note that, as is, your sample data isn't setting IsLastItem...
As is, you have to iterate at least twice, something like this:
items.RemoveAll(x => x.IsLastItem == false &&
items.Any(y => y.ParentId == x.Id) == false);
You're saying to remove all the items where IsLastItem is false and where there's not at least one item whose parent id is that item's id.
You forgot to set IsLastItem in your mocked up data, FYI. You should be able to accomplish this with RemoveAll.
public static void Main()
{
var items = init();
items.RemoveAll(x => !items.Any(y => y.ParentId == x.Id) == true && x.IsLastItem == false);
}
public static List<Item> init()
{
return new List<Item>
{
new Item
{
Id = 1,
ParentId = 0,
Content = "item1"
},
new Item
{
Id = 2,
ParentId = 1,
Content = "item2"
},
new Item
{
Id = 3,
ParentId = 1,
Content = "item3",
IsLastItem = true
},
new Item
{
Id = 4,
ParentId = 1,
Content = "item4"
},
new Item
{
Id = 5,
ParentId = 2,
Content = "item5"
},
new Item
{
Id = 6,
ParentId = 5,
Content = "item6"
},
new Item
{
Id = 7,
ParentId = 5,
Content = "item7"
},
new Item
{
Id = 8,
ParentId = 6,
Content = "item8"
},
new Item
{
Id = 9,
ParentId = 8,
Content = "item9",
IsLastItem = true
}
};
}
Find the ParentIds. Compare each item to the list of ParentId collection and check IsLastitem.
var parents = items.Select(x => x.ParentId);
items.RemoveAll(x => !parents.Contains(x.Id) && !x.IsLastItem);
I would suggest you use a tree-like structure, and make IsLastItem a property that is calculated:
public class Item
{
public int Id { get; set; }
public string Content { get; set; }
public List<Item> SubItems { get; set; }
public bool IsLastItem { get { return SubItems.Count == 0; } }
}
Since the items stored in the database will have a flat structure, you'll have to write a function to create the tree from the database (and write the tree out to the database if necessary), but once that's done, the tree will be easier to manipulate.
You'd then write a recursive function to remove all last nodes, something like this:
List<Item> RemoveNodes(List<Item> tree)
{
var ret = tree.Where(item => !item.IsLastItem);
foreach (Item item in ret)
{
item.SubItems = RemoveNodes(item.SubItems);
}
return ret;
}
That may not be exactly the best way to do it but you get the idea.
I have a list of data structures:
public List<Personal> Personals()
{
return new List<Personal>
{
new Personal
{
Id = 0,
Name = "Name 0"
},
new Personal
{
Id = 1,
Name = "Name 1",
ParentId = 0
},
new Personal
{
Id = 2,
Name = "Name 2",
ParentId = 0
},
new Personal
{
Id = 3,
Name = "Name 3",
ParentId = 0
},
new Personal
{
Id = 4,
Name = "Name 4",
ParentId = 1
},
new Personal
{
Id = 5,
Name = "Name 5",
ParentId = 1
},
new Personal
{
Id = 6,
Name = "Name 6",
ParentId = 2
},
new Personal
{
Id = 7,
Name = "Name 7",
ParentId = 2
},
new Personal
{
Id = 8,
Name = "Name 8",
ParentId = 4
},
new Personal
{
Id = 9,
Name = "Name 9",
ParentId = 4
},
};
}
and I want to build a tree:
public List<Tree> Trees()
{
return new List<Tree>
{
new Tree
{
Id = 0,
Name = "Name 0",
List = new List<Tree>
{
new Tree
{
Id = 1,
Name = "Name 1",
List = new List<Tree>
{
new Tree
{
Id = 4,
Name = "Name 4"
},
new Tree
{
Id = 5,
Name = "Name 5"
}
}
}
}
}
};
}
How do you build a tree with LinQ to object? I have to use but it doesn't work exactly, see below:
public List<Tree> GetTree(List<Personal> list)
{
var listFormat = list.Select(x => new Tree
{
Id = x.Id,
Name = x.Name,
ParentId = x.ParentId
}).ToList();
var lookup = listFormat.ToLookup(f => f.ParentId);
foreach (var tree in listFormat)
{
tree.List = lookup[tree.Id].ToList();
}
return listFormat;
}
You should use recursion:
public void SomeMethod() {
// here you get your `list`
var tree = GetTree(list, 0);
}
public List<Tree> GetTree(List<Personal> list, int parent) {
return list.Where(x => x.ParentId == parent).Select(x => new Tree {
Id = x.Id,
Name = x.Name,
List = GetTree(list, x.Id)
}).ToList();
}
Same as above only this code checks for the case that your root node has a ParentID that matches its own ID.
public void SomeMethod()
{
// here you get your `list`
var tree = GetTree(list, 0);
}
public List<Tree> GetTree(List<Personal> list, int parent)
{
return list.Where(x => x.ParentId == parent).Select(x => new Tree
{
Id = x.Id,
Name = x.Name,
List = x.ParentId != x.Id ? GetTree(list, x.Id) : new List<Tree>()
}).ToList();
}
I have some problem here. Here it is:
I have this class
public class NewsFeedResources
{
public string Name { get; set; }
public string Id { get; set; }
public string Message { get; set; }
public static ObservableCollection<NewsFeedResources> _newsfeed = new ObservableCollection<NewsFeedResources>
{
new NewsFeedResources { Name = "Joe", Id = "1", Message="Foo" },
new NewsFeedResources { Name = "Wandy", Id = "2", Message="Bar" },
new NewsFeedResources { Name = "Yuliana", Id = "3", Message="Baz" },
new NewsFeedResources { Name = "Hardi", Id = "4", Message="Baz" },
};
public static ObservableCollection<NewsFeedResources> newsFeedResources
{ get { return _newsfeed; }
}
}
If I have another data such as
Name=John, Id=5, Message="Stack overflow"
Name=Jane, Id=6, Message="Hello world"
How can I add the data into the class, but not from the constructor? Thanks for the help
ObservableCollection exposes the Collection<T>.Add Method:
Adds an object to the end of the Collection.
So you'd have:
_newsfeed.Add(new NewsFeedResources {Name = "John",
Id = 5,
Message = "Stack overflow"});
_newsfeed.Add(new NewsFeedResources {Name = "Jane",
Id = 6,
Message = "Hello world"});
(typed from memory)
call a function from constructor or anywhere as u like and add items like below
NewsFeedResources NFR=new NewsFeedResources(){Name=John, Id=5, Message="Stack overflow"};
_newsfeed.add(NFR);
NewsFeedResources NFR1 =new NewsFeedResources(){Name=Jane, Id=6, Message="Hello world"};
_newsfeed.add(NFR);