get specific properties within the generic list using linq - c#

I have generic list foo as shown below
var foo = new List<XYZ>();
public class XYZ
{
public String TimeZone { get; set; }
public Decimal? B1Volume { get; set; }
public Decimal? B2Volume { get; set; }
public Decimal? B3Volume { get; set; }
public Decimal? B4Volume { get; set; }
public Decimal? B5Volume { get; set; }
// .............
// .............
public Decimal? B24Volume { get; set; }
public String Name {get;set;}
}
how do I select the properties B1Volume,........B24Volume ?
I tried with following code mentioned below, but it's not giving expected results
var hp = foo.Skip(1).Take(23).ToList();

There's a few ways, but I do not think that you want to go down that road.
Do you really want a list of xyz? Or asked in a different fashion: Do you have many different lists of lists of volumes? Or do you only want to express a single list of volumes?
Maybe what you want to do is declare an array inside XYZ like this
public class XYZ
{
public String TimeZone { get; set; }
public Decimal?[] Volumes {get; set;} = new Decimal?[24];
public String Name {get; set;}
}
If you want to access volumes by an index (1,2,...,24) you need an array or any other kind of indexed data structure.
Then you could do
var xyz = new XYZ();
xyz.Volumes[0] = 12.0;
xyz.Volumes[1] = 23.0;
.....
and basically access the volumes by xyz.Volumes and adding an index to get the n-th volume
If you now want to further list these XYZ you could do something like this:
var listOfXyz = new List<XYZ>();
listOfXyz.Add(new XYZ());
....
listOfXyz[3].Volumes
this would give you the 24 volumes of the element at the index of 3 in the list.

You need to do a Select:
var hp = foo.Select(x => new { x.BVolume1, x.BVolume2, ..., x.BVolume24 });
Although I do agree with #Himzo that this is not the best way to solve your problem if you can change the structure.

Maybe it helps:
XYZ xyz = new XYZ();
Type t = xyz.GetType();
List<PropertyInfo> properties = new List<PropertyInfo>(t.GetProperties());
var hp = properties.Skip(1).Take(23).ToList();
Do not forget adding name space:
using System.Reflection;
Update
In comments GBreen12 suggests to add a filter for getting only properties that has name containing volume. Now if you add another properties the code will not fail. So you can change the 3th line to this:
List<PropertyInfo> properties = (new List<PropertyInfo>(t.GetProperties())).Where(x => x.Name.EndsWith("Volume")).ToList();
Now you do not need last line var hp = ... and the properties is your answer.

Related

How to add items to existing list of objects?

I have three classes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; set; }
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; set; }
}
And I have two Lists in my code like this:
List<M2ArticleMain> data = new List<M2ArticleMain>();
List<M2ArticleAttributeWeb> attb = new List<M2ArticleAttributeWeb>();
In some part of my code firstly I (from foreach loop) add data to attb list where I add only only some data (because I don't have all data at this point), like this:
...
attb.Add(new M2ArticleAttributeWeb
{
Web_id = item.Id, //(item is from foreach loop)
Variants = null //this is **importat**, I left null for later to add it
});
Next, after I fill attb, I add all this to data list:
...
data.Add(new M2ArticleMain
{
Id = item.Id_Pk, //this is also from foreach loop,
Attribut_Web = attb //now in this part I have only data for Web_id and not Variants
}
Now my question is How to Add items later to data list to object Variants?
Something like this:
data.AddRange( "how to point to Variants" = some data);
The M2ArticleAttributeWeb type holding your Variants property is the member of a collection. That is, there are potentially many of them. You can reference an individual Variants property like this:
data[0].Attribut_Web[0].Variants
But you need to know which items you want to add map to which data and Attribut_Web indexes/objects in order to assign them properly. That probably means another loop, or even a nested loop. That is, you can see all of your Variants properties in a loop like this:
foreach(var main in data)
{
foreach(var attrw in main)
{
var v = attrw.Variants;
// do something with v
Console.WriteLine(v);
// **OR**
attrw.Variants = // assign some object
}
}
It's also much better practice to create your collection properties with the object, and then give them private set attributes:
public class M2ArticleMain
{
public int Id { get; set; }
public List<M2ArticleAttributeWeb> Attribut_Web { get; private set; } = new List<M2ArticleAttributeWeb>();
}
public class M2ArticleAttributeWeb
{
public int Web_Id { get; set; }
public M2ArticleTmpMainSkus Variants { get; set; }
}
public class M2ArticleTmpMainSkus
{
public DateTime TimeAdded { get; set; }
public List<string> Skus { get; private set; } = new List<string>();
}
Now instead of assigning Attribut_Web = attb, you would need to .Add() to the existing List.

JSON (deserialized) sends null values to list

Firstly thank you for taking the time to look at this. It's quite alot.
Question:
I'm basically trying to download a json as a string and then deserialize it to a list. The reason why is so i can then call a specific property of that list (in my case 'ips' because it's all i actually need) and insert it into a table if requirements are met.
The problem is that it moves all null values into the array. 114 columns of null, or empty array and i can't figure out why?
I think i'll attach a link to the JSON because its a massive file its here https://endpoints.office.com/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7
Here is my code:
Getters and setters for JSON
public class GetSetJsonIP {
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("serviceArea")]
public string ServiceArea { get; set; }
[JsonProperty("serviceAreaDisplayName")]
public string ServiceAreaDisplayName { get; set; }
[JsonProperty("urls")]
public IList<string> urls { get; set; }
[JsonProperty("ips")]
public IList<string> ips { get; set; }
[JsonProperty("tcpPorts")]
public string tcpPorts { get; set; }
[JsonProperty("expressRoute")]
public bool expressRoute { get; set; }
[JsonProperty("category")]
public string category { get; set; }
[JsonProperty("required")]
public bool required { get; set; }
[JsonProperty("notes")]
public string notes { get; set; }
[JsonProperty("udpPorts")]
public string udpPorts { get; set; }
}
List class
public class ConvertJsonIP{
public List<GetSetJsonIP> jsonIpConvert { get; set; }
public List<GetSetJsonIP> jsonIPConvert = new List<GetSetJsonIP>();
}
3.I download the JSON using an empty string called o365IP
o365IP = wc.DownloadString(wc.BaseAddress + "/endpoints/Worldwide?clientRequestId=b10c5ed1-bad1-445f-b386-b919946339a7");
I deserialize using my List to a seperate var
var o365IpVerion = JsonConvert.DeserializeObject<List<ConvertJsonIP>>(o365IP);
This code shows no errors. so i can only assume its a logical one on my part. It should be noted that i had to put the <List< in to stop an error stating that it couldnt convert an object to an array.
Seriously, i've been stuck on this for 3 days so any help on this would be greatly appreciated! Thanks in advance!
the json you have is a list of objects and each of these objects conform to GetSetJsonIp. You should deserialize using List<GetSetJsonIP>
var o365IpVerion = JsonConvert.DeserializeObject<List<GetSetJsonIP>>(o365IP);
public class GetJsonIP works fine.
The reason you must Deserialize into a List<> is because the json object starts with a bracket making the entire object a List or array.
var O365IpVersion = JsonConvert.DeserializeObject<List<GetJsonIP>(O365IP);
There are different ways to fetch the value of a certain property. If you just need ips and want to check the value then update it, then you could loop:
JArray arr = JArray.Parse(O365IP);
foreach (JObject obj in arr.Children<JObject>())
{
foreach (JPRoperty prop in obj.Properties().Where(x => x.Name == "ips"))
{
//use prop.Value and perform tasks
}
}
Or just simply loop like this:
for (int i = 0; i < O365IpVersion.Count; i++)
{
//use O365IpVersion.ElementAt(i).ips

an array list with n rows and four columns in c#

I need a clear example that shows me how to define a list that has n rows and 4 columns and how to use it. I need a list to save my data like the below image. as you see this could be a dictionary.
You need to create a class with all the above properties
public class Sample
{
public string vocabulary { get; set; }
public string meaning { get; set; }
public int number { get; set; }
public int group { get; set; }
}
and then you can create a List of type Sample,
List<Sample> yourList = new List<Sample>();
You can add items to the list as below
yourList.Add(new Sample { vocabulary = "massive", meaning = "very big", number = 5, group = 15 });
You can access them later like this, if you want the first element,
var result = yourList[0];
this is the easiest and best way of doing it. You need to create a new class and then create new instances of the class and then add it to the list and then use LINQ to get the data out
void Main()
{
var list = new List<myClass>()
list.Add(new myClass() {
Vocabluary = "Vocabluary ",
Meaning = "meaning",
Number = 1,
Group = 2})
}
public class myClass
{
public string Vocabluary { get; set; }
public string Meaning { get; set; }
public int Number { get; set; }
public int Group { get; set; }
}
yes... as Sajeetharan mentioned, with a custom class you can create an any dimensions List. but i don't think you need to think about dimension in C#... it is a bit more high level than that.
just simply create a class and put everything you need in it...
public class CustomClass{
public string d1;
public int d2;
public string d3;
public string d4;
...
//you can easily create a N dimension class
}
to access it and apply it
public void Main(){
List<CustomClass> list = new List<CustomClass>();
CustomClass cc = new CustomClass();
cc.d1 = "v1";
cc.d2 = 0; //v2
list.Add(cc);
//to access it
foreach(CustomClass tmpClass in list)
{
string d1Value = tmpClass.d1;
int d2Value = tmpClass.d2;
}
}

AutoMapper: mapping many properties into one

The scenario is the following: I receive a message containing a lot of variables, several hundreds. I need to write this to Azure Table storage where the partition key is the name of the individual variables and the value gets mapped to e.g. Value.
Let’s say the payload looks like the following:
public class Payload
{
public long DeviceId { get; set; }
public string Name { get; set; }
public double Foo { get; set; }
public double Rpm { get; set; }
public double Temp { get; set; }
public string Status { get; set; }
public DateTime Timestamp { get; set; }
}
And my TableEntry like this:
public class Table : TableEntity
{
public Table(string partitionKey, string rowKey)
{
this.PartitionKey = partitionKey;
this.RowKey = rowKey;
}
public Table() {}
public long DeviceId { get; set; }
public string Name { get; set; }
public double Value { get; set; }
public string Signal { get; set; }
public string Status { get; set; }
}
In order to write that to Table storage, I need to
var table = new Table(primaryKey, payload.Timestamp.ToString(TimestampFormat))
{
DeviceId = payload.DeviceId,
Name = payload.Name,
Status = payload.Status,
Value = value (payload.Foo or payload.Rpm or payload.Temp),
Signal = primarykey/Name of variable ("foo" or "rmp" or "temp"),
Timestamp = payload.Timestamp
};
var insertOperation = TableOperation.Insert(table);
await this.cloudTable.ExecuteAsync(insertOperation);
I don’t want to copy this 900 times (or how many variables there happen to be in the payload message; this is a fixed number).
I could make a method to create the table, but I will still have to call this 900 times.
I thought maybe AutoMapper could help out.
Are they always the same variables? A different approach could be to use DynamicTableEntity in which you basically have a TableEntity where you can fill out all additional fields after the RowKey/PartitionKey Duo:
var tableEntity = new DynamicTableEntity();
tableEntity.PartitionKey = "partitionkey";
tableEntity.RowKey = "rowkey";
dynamic json = JsonConvert.DeserializeObject("{bunch:'of',stuff:'here'}");
foreach(var item in json)
{
tableEntity.Properties.Add(item.displayName, item.value);
}
// Save etc
The problem is to map these properties, it is right?
Value = value (payload.Foo or payload.Rpm or payload.Temp),
Signal = primarykey/Name of variable ("foo" or "rmp" or "temp"),
This conditional mapping can be done via Reflection:
object payload = new A { Id = 1 };
object value = TryGetPropertyValue(payload, "Id", "Name"); //returns 1
payload = new B { Name = "foo" };
value = TryGetPropertyValue(payload, "Id", "Name"); //returns "foo"
.
public object TryGetPropertyValue(object obj, params string[] propertyNames)
{
foreach (var name in propertyNames)
{
PropertyInfo propertyInfo = obj.GetType().GetProperty(name);
if (propertyInfo != null) return propertyInfo.GetValue(obj);
}
throw new ArgumentException();
}
You may map rest of properties (which have equal names in source and destination) with AutoMapper.Mapper.DynamicMap call instead of AutoMapper.Mapper.Map to avoid creation of hundreds configuration maps. Or just cast your payload to dynamic and map it manually.
You can create a DynamicTableEntity from your Payload objects with 1-2 lines of code using TableEntity.Flatten method in the SDK or use the ObjectFlattenerRecomposer Nuget package if you are also worried about ICollection type properties. Assign it PK/RK and write the flattened Payload object into the table as a DynamicTableEntity. When you read it back, read it as DynamicTableEntity and you can use TableEntity.ConvertBack method to recreate the original object. Dont even need that intermediate Table class.

Use LINQ to transform single object into IEnumerable via Properties/reflection?

I have a simple object like such:
public class Foo {
public int One { get; set; }
public int Two { get; set; }
....
public int Eleven { get; set; }
}
Given an IEnumerable, what I want is a LINQ method to transform as such:
myFooEnumerable.Select(n => transformMagicGoesHere);
Where my return object looks like this:
public class Bar {
public string DurationDescription {get;set;} //Value would be "One" or "Two" or ...
public int Value {get;set;} //Holds value in the property One or Two or ...
}
So for every item N in myFooEnumerable in the example above I'd get 11(N) items in my resultant select statement.
This should do it:
var bars = myFooEnumerable.SelectMany(
x => x.GetType().GetProperties().Select(p => new Bar {
DurationDescription = p.Name,
Value = (int)p.GetValue(x)
}));
Not a great thing to be doing in the first place, IMO, but it will at least work.

Categories