Unfortunately I m new to Lambda/ Linq and I need to get data from a list. Below is my existing code:
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Bubble, ZoomType = ZoomTypes.Xy, Width = 600, Height = 400 })
.SetTitle(new Title { Text = "Highcharts Bubbles" })
.SetSeries(new[]
{
new Series
{
Name="Buy",
Data = new Data(new object[]
{
new object[] {97,36,79 },
new object[] { 94,74,60 },
new object[] { 68,76,58 }
})
}
});
Lines of code which need to be replaced are:
new object[] {97,36,79 },
new object[] { 94,74,60 },
new object[] { 68,76,58 }
In above code inside {} instead of hardcoded values for example 97, 36, 79 in first line I need to pass values from transactions (transaction volume, price and termdate).
(it is just like using foreach loop but I have to do it using Lambda/ Linq.) I can query all transactions in list transaction.
My poco class is:
public class Transaction : SearchCondition, Automappable
{
[ScriptIgnore]
public virtual int Id { get; set; }
public virtual decimal Volume { get; set; }
public virtual decimal Price { get; set; }
public virtual DateTime TermDate { get; set; }
}
Can you please help me modifying code.
I highly appreciate your time, guidance and help.
EDIT
I have tried the ways mentioned in below solutions, it is almost what is required but still a small issue.
Below codes are able to supply data but they cover data with an additional array. To clear it more please see below image of incorrect structure:
It do not show an error but because of that I am not able to use data.
Below is a snap short of correct data structure.
Can you please help a little more.
How about generating the array like this, where transactionList is your list of transactions:
Data = new Data(transactionList
.Select(i => new object[]
{i.Volume, i.Price, i.TermDate} as object)
.ToArray();
Here you create multiple arrays of objects, one for each of your transaction records. Each of these arrays is treated as a single object in the final array.
Select works by mapping each element of an input IEnumerable (in your case, transactionList), to a function of the element. In your case, your function (the lambda expression inside the Select statement) takes each element, and extract fields into an object array.
The whole operation returns an IEnumerable of object - but your Data constructor takes an object array. So we have to call ToArray() to convert to an object[].
Have you tried using one of the above solutions but not selecting an Array of Arrays?
Using a List<Transaction> called transactions:
Data = new Data(transactions.Select(t => t).ToArray());
This is assuming that the transactions IEnumerable is a collection of Transaction objects, in which case you just want to select every object in the array and pass to the Data classes constructor.
Alternatively, you could also do:
Data = new Data(transactions);
I you have a List<Transaction> object named tList, then your data line would look like this:
Data = new Data(tList
// for each item in the list
.Select(
// create an array of the values we care about
item => new object[] { item.Volume, item.Price, item.TermDate })
// put each of those results into an array
.ToArray());
If you have an IEnumerable of objects you can use the Linq Select method to transform it into an IEnumerable of a different type.
The Select statement takes as a parameter a lambda expression which takes one item from the source IEnumerable and returns a (usually) different type. The results of the lambda expression become the items in a new IEnumerable.
In your case, let's assume that you have a List<Transaction> called transactions that contains all of the Transaction objects you want to display in the graph. Assuming that the items in the list are already sorted into the correct order, you can use the following code to create your Data instance:
Data = new Data(
transactions.Select(t =>
(object)new object[] { t.Volume, t.Price, t.TermDate}
)
.ToArray()
)
In this code the Select method is used to convert your List<Transaction> to IEnumerable<object>, which the ToArray method then converts to object[].
If you need to you can do conversions and calculations on the data inside the lambda expression:
Data = new Data(
transactions.Select(t =>
(object)new object[]
{
(int)t.Volume,
(int)t.Price,
t.TermDate.DayOfYear
}
)
.ToArray()
)
(Edited to return object[] instead of object[][])
Related
So let's say that you have 2 series of data. (Both object arrays, in your choice of a serialized JSON string, or the actual objects).
For Instance:
string str1 = #"{""datapoints"":[[""02/28/2019"",146800.0],[""02/27/2019"",147700.0],[""02/26/2019"",153900.0]]}";
Then, you have a second series that is very similar...
string str2 = #"{""datapoints"":[[""02/28/2019"",145600.0],[""02/27/2019"",143600.0],[""02/26/2019"",152200.0]]}";
Note: the object arrays inside are both a length of "2", and both contain the same "date" as the [0] index.
How does one merge the 2 object arrays into 1, to yield the following output...
string str3 = #"{""datapoints"":[[""02/28/2019"",145600.0,145600.0],[""02/27/2019"",143600.0,143600.0],[""02/26/2019"",152200.0,152200.0]]}";
For clarity, I'm interested in using the [0] index once, and merging the [1] indexes together. (the number values)
Extra credit if this can be a loop, or can be done with any number of series.
Using json.net, you can deserialize each JSON sample to an object that contains a datapoints property that is an enumerable of object arrays, then merge them using the LINQ methods GroupBy() and Aggregate().
Say the JSON samples to be merged are in a string [][] jsonSeriesList like so:
string str1 = #"{""datapoints"":[[""02/28/2019"",146800.0],[""02/27/2019"",147700.0],[""02/26/2019"",153900.0]]}";
string str2 = #"{""datapoints"":[[""02/28/2019"",145600.0],[""02/27/2019"",143600.0],[""02/26/2019"",152200.0]]}";
var jsonSeriesList = new[] { str1, str2 }; // Add others as required
Then you can create a combined series as follows:
var merged = jsonSeriesList.Aggregate(
new { datapoints = Enumerable.Empty<object[]>() },
(m, j) => new
{
datapoints = m.datapoints.Concat(JsonConvert.DeserializeAnonymousType(j, m).datapoints)
// Group them by the first array item.
// This will throw an exception if any of the arrays are empty.
.GroupBy(i => i[0])
// And create a combined array consisting of the key (the first item from all the grouped arrays)
// concatenated with all subsequent items in the grouped arrays.
.Select(g => new[] { g.Key }.Concat(g.SelectMany(i => i.Skip(1))).ToArray())
});
var mergedJson = JsonConvert.SerializeObject(merged);
Notes:
I am deserializing to an anonymous type for brevity. You could create an explicit data model if you prefer.
I am assuming the individual datapoint arrays all have at least one item.
There is no attempt to sort the resulting merged JSON by series date. You could do that if necessary.
The solution assumes that you will never have multiple component arrays in the same series with the same first item, e.g. "02/28/2019" repeated twice. If so, they will get merged also.
Sample .Net fiddle here.
Here is a simplified example (simplified as validations might be required, but hope it given you a place to start):
Convert it into dot net object
Then go through each date point - for each date point go through all the series, adding the values.
//container object for the json series
public class Container
{
public List<List<object>> datapoints;
}
//Input series in JSON
string[] inputSeries = new string[]
{
"{\"datapoints\": [[\"02/28/2019\", 146800.0],[\"02/27/2019\", 147700.0],[\"02/26/2019\", 153900.0]]}",
"{\"datapoints\": [[\"02/28/2019\", 145600.0],[\"02/27/2019\", 143600.0],[\"02/26/2019\", 152200.0]]}"
};
//Container for input series in dot net object
List<Container> con = new List<Container>();
foreach (var series in inputSeries)
{
con.Add(JsonConvert.DeserializeObject<Container>(series));
}
// output container
Container output = new Container();
output.datapoints = new List<List<object>>();
// assuming all series have equal number of data points.....might not be so
for (int i = 0; i < con[0].datapoints.Count; i++)
{
output.datapoints.Add(new List<object>());
// inner loop is to go across series for the same datapoint....
for (int j = 0; j < con.Count; j++)
{
// add the date if this is the first series....after that only add the values
// right now the assumption is that the dates are in order and match....validation logic might be required
if (j == 0)
{
output.datapoints[i].Add(con[j].datapoints[i][0]);
output.datapoints[i].Add(con[j].datapoints[i][1]);
}
else
{
output.datapoints[i].Add(con[j].datapoints[i][1]);
}
}
}
So I have
List<string[]> listy = new List<string[]>();
listy.add('a','1','blue');
listy.add('b','2','yellow');
And i want to search through all of the list ti find the index where the array containing 'yellow' is, and return the first element value, in this case 'b'.
Is there a way to do this with built in functions or am i going to need to write my own search here?
Relatively new to c# and not aware of good practice or all the built in functions. Lists and arrays im ok with but lists of arrays baffles me somewhat.
Thanks in advance.
As others have already suggested, the easiest way to do this involves a very powerful C# feature called LINQ ("Language INtegrated Queries). It gives you a SQL-like syntax for querying collections of objects (or databases, or XML documents, or JSON documents).
To make LINQ work, you will need to add this at the top of your source code file:
using System.Linq;
Then you can write:
IEnumerable<string> yellowThings =
from stringArray in listy
where stringArray.Contains("yellow")
select stringArray[0];
Or equivalently:
IEnumerable<string> yellowThings =
listy.Where(strings => strings.Contains("yellow"))
.Select(strings => strings[0]);
At this point, yellowThings is an object containing a description of the query that you want to run. You can write other LINQ queries on top of it if you want, and it won't actually perform the search until you ask to see the results.
You now have several options...
Loop over the yellow things:
foreach(string thing in yellowThings)
{
// do something with thing...
}
(Don't do this more than once, otherwise the query will be evaluated repeatedly.)
Get a list or array :
List<string> listOfYellowThings = yellowThings.ToList();
string[] arrayOfYellowThings = yellowThings.ToArray();
If you expect to have exactly one yellow thing:
string result = yellowThings.Single();
// Will throw an exception if the number of matches is zero or greater than 1
If you expect to have either zero or one yellow things:
string result = yellowThings.SingleOrDefault();
// result will be null if there are no matches.
// An exception will be thrown if there is more than one match.
If you expect to have one or more yellow things, but only want the first one:
string result = yellowThings.First();
// Will throw an exception if there are no yellow things
If you expect to have zero or more yellow things, but only want the first one if it exists:
string result = yellowThings.FirstOrDefault();
// result will be null if there are no yellow things.
Based on the problem explanation provided by you following is the solution I can suggest.
List<string[]> listy = new List<string[]>();
listy.Add(new string[] { "a", "1", "blue"});
listy.Add(new string[] { "b", "2", "yellow"});
var target = listy.FirstOrDefault(item => item.Contains("yellow"));
if (target != null)
{
Console.WriteLine(target[0]);
}
This should solve your issue. Let me know if I am missing any use case here.
You might consider changing the data structure,
Have a class for your data as follows,
public class Myclas
{
public string name { get; set; }
public int id { get; set; }
public string color { get; set; }
}
And then,
static void Main(string[] args)
{
List<Myclas> listy = new List<Myclas>();
listy.Add(new Myclas { name = "a", id = 1, color = "blue" });
listy.Add(new Myclas { name = "b", id = 1, color = "yellow" });
var result = listy.FirstOrDefault(t => t.color == "yellow");
}
Your current situation is
List<string[]> listy = new List<string[]>();
listy.Add(new string[]{"a","1","blue"});
listy.Add(new string[]{"b","2","yellow"});
Now there are Linq methods, so this is what you're trying to do
var result = listy.FirstOrDefault(x => x.Contains("yellow"))?[0];
I am new to the System.Linq.Dynamic.Core. I have this:
Let's say we have:
Packs = new List<Pack>
{
new Pack()
{
IdAtSource="Pack1",
Equipments= new List<Equipment>()
{
new Equipment
{
Id=1,
GenericEquipment = new GenericEquipment()
{
Id=7
}
}
}
},
new Pack()
{
IdAtSource="Pack2",
Equipments= new List<Equipment>()
{
new Equipment
{
Id=2,
GenericEquipment = new GenericEquipment()
{
Id=1
}
},
new Equipment
{
Id=2,
GenericEquipment = new GenericEquipment()
{
Id=2
}
}
}
}
}
I would like to select the Packs with Equipments, but in the selected Equipments I need to have only the one with Id=2 for Generic Equipment.(the result should contain a list of packs with list of equipments).
I've tried this:
querable.Where("Packs.Equipments.Select((GenericEquipment.Id)=1)");
but I feel I am waaay of target here. Also is there any documentation page on how to use this library?
Thanks a lot
The most recent version of Dynamic LINQ appears to be the project here, with the documentation here.
Generally, the only reason why you should require Dynamic LINQ over standard LINQ is when the types are not known at compile time.
If you know at compile time that the query will be against a List<Pack>, you can use stanadard LINQ, as in the following code (note that this modifies the original instances of Pack):
var usefulPacks = Packs.Select(pack => {
pack.Equipments = pack.Equipments.Where(equipment =>
equipment.GenericEquipment.Id == 1
).ToList();
}).Where(pack => pack.Equipments.Any()).ToList();
If you need code that doesn't modify the original instances, this code creates copies of the original instances:
var usefulPacks = Packs.Select(pack => {
return new Pack() {
IDAtSource = pack.IDAtSource,
Equipments = pack.Equipments.Where(equipment =>
equipment.GenericEquipment.Id == 1
).ToList();
};
}).Where(pack => pack.Equipments.Any()).ToList();
Note that this isn't using .SelectMany — .SelectMany is used to create a single enumerable from nested enumerables; here each Pack in the final list corresponds to a Pack in the original list.
Dynamic LINQ doesn't support modifying or initializing properties as part of the expression:
The expression language permits getting (but not setting) the value of any reachable public field, property, or indexer.
so the Equipments property cannot be changed / initialized to include only instances of Equipment that match the criteria.
In order to set the Equipments, you have two choices:
Add a constructor to Pack which takes the appropriate arguments
Write a static method on any class which takes the appropriate arguments
Add a constructor to Pack
You can add a constructor to Pack with the appropriate arguments, that sets Equipments:
Pack(int IDAtSource, IEnumerable<Equipment> equipments) {
this.IDAtSource = IDAtSource;
this.Equipments = equipments.ToList();
}
Then you could use the following:
IQueryable qry = Packs.AsQueryable();
qry = qry
.Select("Pack(IDAtSource, Equipments.Where(GenericEquipment.ID=1))")
.Where("Equipments.Any");
Define a static method
public static class MyPackMethods {
public static Pack Create(int IDAtSource, IEnumerable<Equipment> equipments) {
return new Pack() {
IDAtSource = IDAtSource,
Equipments = equipments.ToList()
};
}
}
and call:
IQueryable qry = Packs.AsQueryable();
qry = qry
.Select("MyPackMethods.Create(IDAtSource, Equipments.Where(GenericEquipment.ID=1))")
.Where("Equipments.Any");
These should work:
var equipments= from pack in Packs where pack.Equipments.Any() select pack.Equipments;
var secondEquipments = from pac in equipments where
pac.GenericEquipment.Id == 2 select pac;
//I could use one variable instead of 2 but that would look a little bit complex
Msdn Link(Sorry I'm at mobile so I can't rename it):
https://msdn.microsoft.com/en-us/library/bb397927.aspx
I have a table on my Database where, aside from other columns (one of which is a UniqueIdentifier) I also have one column where I have a JSON array string with values like this (formatted):
[
{
"AttributeId": "fe153d69-8ac1-6e0c-8793-ff0000804eb3",
"AttributeValueId": "64163d69-8ac1-6e0c-8793-ff0000804eb3"
},
{
"AttributeId": "00163d69-8ac1-6e0c-8793-ff0000804eb3",
"AttributeValueId": "67163d69-8ac1-6e0c-8793-ff0000804eb3"
}
]
I then have this AttributeValuePair class which will allow me to read this data on code:
public class AttributeValuePair
{
public AttributeValuePair();
public Guid AttributeId { get; set; }
public Guid AttributeValueId { get; set; }
}
Whenever I get a list of items from this table, I want to be able to filter the resulting array based on only one AttributeValueId and get only the items where this is a match, independently of the value of any other attributes.
Since that on code, to read these attribute collection I must have a List<AttributeValuePair>, how in LINQ can I get the items where a particular AttributeValueId is present?
List<AttributeValuePair> attributeValuePairs = serializer.Deserialize<List<AttributeValuePair>>(item.Variant);
I've been lost at it for two hours already and can't seem to find an escape from this one.
EDIT
Being more clear about the problem, what I'm trying to do is, from a List<ProductVariation>, get the possible values for the attribute "Portions", when the attribute "Days" is the specified value. I'm having a lot of trouble using the serializer to build the LINQ statement.
//This code is wrong, I know, but I'm trying to show what I want
result = model.ProductVariations.Find(x, new {serializer.Deserialize<List<AttributeValuePair>>(item.Variant).Where(valuePair => valuePair.AttributeId == attributeId)});
Can you try
attributeValuePairs.Where(valuePair => valuePair.AttributeId == new Guid("SomeValue"));
The answer to this question was actually a lot simpler than previously expected:
public string SelectedVariation(string mealsAttribute, string portionsAttribute, string product)
{
Guid productId = new Guid(product);
CatalogManager catalogManager = CatalogManager.GetManager();
EcommerceManager ecommerceManager = EcommerceManager.GetManager();
RegisterOrderAccountFormModel model = new RegisterOrderAccountFormModel();
model.Product = catalogManager.GetProduct(productId);
List<ProductVariation> productVariationsCollection = catalogManager.GetProductVariations(productId).ToList();
//This is the really interesting part for the answer:
return productVariationsCollection.Where(x => x.Variant.ToLower().Contains(mealsAttribute.ToLower()) && x.Variant.ToLower().Contains(portionsAttribute.ToLower())).FirstOrDefault().Id.ToString();
}
This is a question probably not just of what collection to use, but what methods are best to use to access the data once it is defined. I am a relative newbie to C# and .NET, but I have been through a couple simple projects and need some direction on doing searches on smaller sets of static data. Specifically I have a class defined similar to this:
public class rlsSoftwareVersions
{
public double dReleaseNum { get; set; }
public string strReleaseName { get; set; }
public long lConfigSchema { get; set; }
public long lProgramSchema { get; set; }
}
We have a straightforward array of those class objects defined as follows:
static rlsSoftwareVersions[] rlsSoftware = {
new rlsSoftwareVersions { dReleaseNum = 4.0, strReleaseName = "Chronos", lConfigSchema = 0x04, lProgramSchema = 0x0DB4 },
new rlsSoftwareVersions { dReleaseNum = 4.1, strReleaseName = "Hera", lConfigSchema = 0x06, lProgramSchema = 0x0DB5 },
new rlsSoftwareVersions { dReleaseNum = 5.0, strReleaseName = "Zeus", lConfigSchema = 0x0C, lProgramSchema = 0x0DB5 },
new rlsSoftwareVersions { dReleaseNum = 5.1, strReleaseName = "Poseidon",lConfigSchema = 0x0C, lProgramSchema = 0x0DBB }
.. .. .. ..
.. .. .. ..
.. .. .. ..
};
That array extends for about 30 more entries. My question is this. I have been going through learning about using Dictionaries for doing searches by index. But that seems to allow searching on one index only. What I need is to be able to access this kind of data (in the array) by searching based on any of the properties and getting a returned collection of the values in the other member properties of matching objects.
For example, in one case, I want to get the collection of values for lConfigSchema that return when I match the dReleaseNum property to 4.0. Then, the next time I want the collection of values for dReleaseNum, then the lConfigSchema property is equal to 0x0C. I want to basically do this kind of look up on any property and get the results (Collection) of any other associated property.
I am just finishing up looking through dictionaries, but they appear to only work with a single index. I am either looking at this wrong or looking at using the wrong kind of class to do this. Any direction suggestions you can push me towards? It feels like I am trying to use a hammer when I should be using a knife..
Caveat: I can't create a DB for this. It needs to all be in a single resultant executable without external database or files. Which is why I created the internal static array...
Thanks
Why not using LINQ?
IEnumerable<rlsSoftwareVersions> result = rlsSoftwareVersions.Where(item => item.dReleaseNumber == 4.0);
foreach(var rlsSoftwareVersion in result)
{
// do something
}
here are some useful examples: https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b