LINQ get items in List<AttributeValuePair> - c#

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();
}

Related

Grouping and sum

I have a list as follows which will contain the following poco class.
public class BoxReportView
{
public DateTime ProductionPlanWeekStarting { get; set; }
public DateTime ProductionPlanWeekEnding { get; set; }
public string BatchNumber { get; set; }
public string BoxRef { get; set; }
public string BoxName { get; set; }
public decimal Qty { get; set; }
public FUEL_KitItem KitItem { get; set; }
public decimal Multiplier { get; set; }
}
I am wanting to group the report and sum it by using the BoxName and also the Qty SO I tried the following
var results = from line in kitItemsToGroup
group line by line.BoxName into g
select new BoxReportView
{
BoxRef = g.First().BoxRef,
BoxName = g.First().BoxName,
Qty = g.Count()
};
In My old report I was just doing this
var multiplier = finishedItem.SOPOrderReturnLine.LineQuantity -
finishedItem.SOPOrderReturnLine.StockUnitDespatchReceiptQuantity;
foreach (KitItem kItem in kitItems.Cast<KitItem().Where(z => z.IsBox == true).ToList())
{
kittItemsToGroup.Add(new BoxReportView() {
BatchNumber = _batchNumber,
ProductionPlanWeekEnding = _weekEndDate,
ProductionPlanWeekStarting = _weekStartDate,
BoxRef = kItem.StockCode,
KitItem = kItem,
Multiplier = multiplier,
Qty = kItem.Qty });
}
}
Then I was just returning
return kitItemsToGroup;
But as I am using it as a var I cannot what is best way to handle the grouping and the sum by box name and qty.
Whether it is the best way depends upon your priorities. Is processing speed important, or is it more important that the code is easy to understand, easy to test, easy to change and easy to debug?
One of the advantages of LINQ is, that it tries to avoid enumeration of the source more than necessary.
Are you sure that the users of this code will always need the complete collection? Can it be, that now, or in near future, someone only wants the first element? Or decides to stop enumeration after he fetched the 20th element and saw that there was nothing of interest for him?
When using LINQ, try to return IEnumerable<...> as long as possible. Let only the end-user who will interpret your LINQed data decide whether he wants to take only the FirstOrDefault(), or Count() everything, or put it in a Dictionary, or whatever. It is a waste of processing power to create a List if it is not going to be used as a List.
your LINQ code and your foreach do some completely different things. Alas it is quite common here on StackOverflow for people to ask for LINQ statements without really specifying their requirements. So I'll have to guess something in between your LINQ statement and your foreach.
Requirement Group the input sequence of kitItems, which are expected to be Fuel_KitItems into groups of BoxReportViews with the same BoxName, and select several properties from every Fuel_KitItem in each group.
var kitItemGroups = kitItems
.Cast<Fuel_KitItem>() // only needed if kitItems is not IEnumerable<Fuel_KitItem>
// make groups of Fuel_KitItems with same BoxName:
.GroupBy(fuelKitItem => fuelKitItem.BoxName,
// ResultSelector, take the BoxName and all fuelKitItems with this BoxName:
(boxName, fuelKitItemsWithThisBoxName) => new
{
// Select only the properties you plan to use:
BoxName = boxName,
FuelKitItems = fuelKitItemsWithThisBoxName.Select(fuelKitItem => new
{
// Only Select the properties that you plan to use
BatchNumber = fuelKitItem.BatchNumber,
Qty = fuelKitItem.Qty,
...
// Not needed, they are all equal to boxName:
// BoxName = fuelKitItem.BoxName
})
// only do ToList if you are certain that the user of the result
// will need the complete list of fuelKitItems in this group
.ToList(),
});
Usage:
var kitItemGroups = ...
// I only need the KitItemGroups with a BoxName starting with "A"
var result1 = kitItemGroups.Where(group => group.BoxName.StartsWith("A"))
.ToList();
// Or I only want the first three after sorting by group size
var result2 = kitItemGroups.OrderBy(group => group.FuelKitItems.Count())
.Take(3)
.ToList();
Efficiency Improvements: As long as you don't know how your LINQ will be used, don't make it a List. If you know that chances are high that the Count of group.FuelKitItems is needed, to a ToList

Searching a static array on Multiple Indexes C#

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

Updating entire node with mutating cypher in Neo4jclient

I need to update all the properties of a given node, using mutating cypher. I want to move away from Node and NodeReference because I understand they are deprecated, so can't use IGraphClient.Update. I'm very new to mutating cypher. I'm writing in C#, using Neo4jclient as the interface to Neo4j.
I did the following code which updates the "Name" property of a "resunit" where property "UniqueId" equals 2. This works fine. However,
* my resunit object has many properties
* I don't know which properties have changed
* I'm trying to write code that will work with different types of objects (with different properties)
It was possible with IGraphClient.Update to pass in an entire object and it would take care of creating cypher that sets all properies.
Can I somehow pass in my object with mutating cypher as well?
The only alternative I can see is to reflect over the object to find all properties and generate .Set for each, which I'd like to avoid. Please tell me if I'm on the wrong track here.
string newName = "A welcoming home";
var query2 = agencyDataAccessor
.GetAgencyByKey(requestingUser.AgencyKey)
.Match("(agency)-[:HAS_RESUNIT_NODE]->(categoryResUnitNode)-[:THE_UNIT_NODE]->(resunit)")
.Where("resunit.UniqueId = {uniqueId}")
.WithParams(new { uniqueId = 2 })
.With("resunit")
.Set("resunit.Name = {residentialUnitName}")
.WithParams(new { residentialUnitName = newName });
query2.ExecuteWithoutResults();
It is indeed possible to pass an entire object! Below I have an object called Thing defined as such:
public class Thing
{
public int Id { get; set; }
public string Value { get; set; }
public DateTimeOffset Date { get; set; }
public int AnInt { get; set; }
}
Then the following code creates a new Thing and inserts it into the DB, then get's it back and updates it just by using one Set command:
Thing thing = new Thing{AnInt = 12, Date = new DateTimeOffset(DateTime.Now), Value = "Foo", Id = 1};
gc.Cypher
.Create("(n:Test {thingParam})")
.WithParam("thingParam", thing)
.ExecuteWithoutResults();
var thingRes = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes.Id, thingRes.Value, thingRes.AnInt, thingRes.Date);
thingRes.AnInt += 100;
thingRes.Value = "Bar";
thingRes.Date = thingRes.Date.AddMonths(1);
gc.Cypher
.Match("(n:Test)")
.Where((Thing n) => n.Id == 1)
.Set("n = {thingParam}")
.WithParam("thingParam", thingRes)
.ExecuteWithoutResults();
var thingRes2 = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes2.Id, thingRes2.Value, thingRes2.AnInt, thingRes2.Date);
Which gives:
Found: 1,Foo,12,2014-03-27 15:37:49 +00:00
Found: 1,Bar,112,2014-04-27 15:37:49 +00:00
All properties nicely updated!

List<object> Self-Filter

I have a list like
List<VoieData> listVoieData = new List<VoieData>();
and in VoieData Class I have :
public class VoieData
{
public int Depart { set; get; }
public int Arrive { set; get; }
public int DistanceDepart { set; get; }
public int DistanceArrive { set; get; }
}
Since I have a massive values I want to only consider all my Depart number , I would like to filter the listVoieData by finding the Arrive only have the same value as the
Depart
for example I have
listVoieData.Select(p=>p.Depart).ToList()= List<int>{1,2,3};
listVoieData.Select(p=>p.Arrive).ToList()= List<int>{1,2,3,4,5};
I need to throw away the entire VoieData which contain {4,5} as Arrive
right now my soulution is like this , but it' s not correct ;
List<VoieData> listVoieDataFilter = listVoieData .Join(listVoieData , o1 => o1.Arrive, o2 => o2.Depart, (o1, o2) => o1).ToList();
Sorry for the confusing question ;
I want to remove Arrive which is different from all the Depart in the list list , and return the new
List
it 's not only in one VoieData;
Arrive!=Depart
Thanks
I think you want to remove all objects where Arrive is not in any of the Depart from any object. In that case, first get all Depart and then filter by Arrive:
HashSet<int> allDepart = new HashSet<int>(listVoieData.Select(x => x.Depart));
var result = listVoieData.Where(v => !allDepart.Contains(v.Arrive))
We use a HashSet<int> for efficiency.
Use LINQ Where:
var records = listVoieData.Where(x => x.Arrive == x.Depart);
This will return results where both Arrive and Depart are the same.
That would be a typical case to use linq.
something like:
var res = from data in listVoieData
where data.Depart == data.Arrive
select data;
and then optionally just use res.ToArray() to run the query and get the array.
Since you've stated that you want:
I want to remove Arrive which is different from all the Depart
This can be re-phrased as, "The set of all arrivals except those in the set of departures", which translates very nicely into the following LINQ query:
var arrivalsWithNoDepartures = listVoieData.Select(p=>p.Arrive)
.Except(listVoieData.Select(p=>p.Depart));

How do i get the difference in two lists in C#?

Ok so I have two lists in C#
List<Attribute> attributes = new List<Attribute>();
List<string> songs = new List<string>();
one is of strings and and one is of a attribute object that i created..very simple
class Attribute
{
public string size { get; set; }
public string link { get; set; }
public string name { get; set; }
public Attribute(){}
public Attribute(string s, string l, string n)
{
size = s;
link = l;
name = n;
}
}
I now have to compare to see what songs are not in the attributes name so for example
songs.Add("something");
songs.Add("another");
songs.Add("yet another");
Attribute a = new Attribute("500", "http://google.com", "something" );
attributes.Add(a);
I want a way to return "another" and "yet another" because they are not in the attributes list name
so for pseudocode
difference = songs - attributes.names
var difference = songs.Except(attributes.Select(s=>s.name)).ToList();
edit
Added ToList() to make it a list
It's worth pointing out that the answers posted here will return a list of songs not present in attributes.names, but it won't give you a list of attributes.names not present in songs.
While this is what the OP wanted, the title may be a little misleading, especially if (like me) you came here looking for a way to check whether the contents of two lists differ. If this is what you want, you can use the following:-
var differences = new HashSet(songs);
differences.SymmetricExceptWith(attributes.Select(a => a.name));
if (differences.Any())
{
// The lists differ.
}
This is the way to find all the songs which aren't included in attributes names:
var result = songs
.Where(!attributes.Select(a => a.name).ToList().Contains(song));
The answer using Except is also perfect and probably more efficient.
EDIT: This sintax has one advantage if you're using it in LINQ to SQL: it translates into a NOT IN SQL predicate. Except is not translated to anything in SQL. So, in that context, all the records would be recovered from the database and excepted on the app side, which is much less efficient.
var diff = songs.Except(attributes.Select(a => a.name)).ToList();

Categories