Linq To Objects C# - c#

I want to get a collection of Bonds and their associate collection of maturities where the maturity.matamount > 200000.
edit:(I only want the maturity collection of each bond to include maturities > 200000)
Here is a program.cs that has the class defs and a method to populate test data for the query.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LinqToObjects
{
class Program
{
static void Main(string[] args)
{
Program.QueryCollection();
Console.ReadLine();
}
public static void QueryCollection()
{
List<Bond> bonds = Program.BuildCollections();
//how do I get a list of Bonds that have a maturity.MatAmount > 200,000?
}
public static List<Bond> BuildCollections()
{
List<Bond> bonds = new List<Bond>();
Bond bond;
for (int i = 1; i <= 10; i++)
{
bond = new Bond() {ID = i, Title = "Bond Title " + i.ToString() };
for (int j = 1; j <= 10; j++)
{
bond.Maturities.Add(new Maturity(){ID = j, BondID = i, MatDate = DateTime.Today.AddDays(j), MatAmount = 152000 * j});
}
bonds.Add(bond);
}
return bonds;
}
}
public class Bond
{
public int ID { get; set; }
public string Title { get; set; }
public List<Maturity> Maturities { get; set; }
public Bond()
{
Maturities = new List<Maturity>();
}
}
public class Maturity
{
public int ID { get; set; }
public int BondID { get; set; }
public DateTime MatDate { get; set; }
public int MatAmount { get; set; }
}
}

How about this?
IEnumerable<Bond> bigBonds = bonds.Where(b => b.Maturities.Any(m => m.MatAmount > 200000));

I'm not exactly sure what you are looking for but to get your bonds just do something like this:
var filteredBonds =
(
from bond in bonds
join maturity in maturities on bond.ID equals maturity.BondID
where maturity.MatAmount > 200000
select new { bond.ID, bond.Title, maturity.MatAmount, maturity.MatDate }
).ToList();
The ToArray() is optional, you could leave things in the table form if you like. I'm not really sure what you want to do with your results.
You might also want to decouple your Bonds and Maturities in your data structure. I don't think you really need to have a list of Maturities is you are storing the BondID as a member of a maturity object. It seems a little redundant, but honestly I don't use Linq so maybe that is the way to go. Your call.

Related

sql where clause rule in linq

I'm trying to put my SQL rule in Linq , as my rule get generated from query builder and I need to filter my data based on rule , this is my simple example
class Program
{
static void Main(string[] args)
{
PromotionVm lObjPromVm = new PromotionVm();
for (int i = 1; i <= 5; i++)
{
PromotionList lObjPromList = new PromotionList();
lObjPromList.active_indicator = 1;
lObjPromList.principle_code = "a" + i;
lObjPromList.promotion_code = "b" + i;
lObjPromList.promotion_plan_number = 20 + i;
lObjPromList.promotion_type_code = 30 + i;
lObjPromList.start_date = DateTime.Now.AddDays(i);
lObjPromVm.promotion_list.Add(lObjPromList);
}
//var sqlRule= "promotion_type_code = 'expensive' AND Category IN('Food', 'Transportation', 'Shopping') AND(PaymentMode = 'Cash' OR PaymentMode = 'Debit Card' OR(Amount = 35))";
var sqlRule = "promotion_type_code = '33'";
// lObjPromVm.promotion_list.ToDataTable()
var lOutlut = lObjPromVm.promotion_list.Where(sqlRule);
}
}
class PromotionVm
{
public List<PromotionList> promotion_list { get; set; }
public PromotionVm()
{
promotion_list = new List<PromotionList>();
}
}
public class PromotionList
{
public string principle_code { get; set; }
public string promotion_code { get; set; }
public int promotion_plan_number { get; set; }
public int promotion_type_code { get; set; }
public DateTime start_date { get; set; }
public int active_indicator { get; set; }
}
I'm trying to use System.Linq.Dynamic.Core; but not working.
Can anyone suggest how I can filter my data by SQL rules?
same question was asked here How to use a string in the linq where clause?
but response what is given , its not working .
I was able to solve the problem , I just needed to convert to AsQueryable() .
var sqlRule = "promotion_type_code in (31,33) or (promotion_code=\"b2\")";
var lOutlut = lObjPromVm.promotion_list.AsQueryable().Where(sqlRule);

C# Linq - Select Multiple Fields where one field should also be filtered with a select

I'm a little bit stuck in Linq.
So first - I show you first the entities. I have a List let's name it "PersonalList" with another List of ListMembers.
public class PersonalList
{
public PersonalList();
public List<ListMember> ListMembers { get; set; }
public long ListNumber {get; set; }
public string Description {get; set;}
}
Here is the ListMember Class:
public class ListMember
{
public ListMember();
public string MemberName{ get; set; }
public long ListId {get; set; }
public string MemberType {get; set; }
public string Position {get; set; }
}
So now im my AppClass I have a List of the PersonalLists.
And I want to create a Dictionary, which has the PersonalList.ListNumber as Key and the Value should be the MemberName AND the MemberType.
What I have tried in first step is:
var personalLists = _allPersonalLists.Select(x => new {x.ListNumber, x.ListMembers).ToArray();
This solves the Problem with ListNumbers as Key. Now I want to have the ListMembers to be filtered so I have tried:
var personalLists = _allPersonalLists.Select(x => new {x.ListNumber, x.ListMembers.Select(y => new {y.MemberName, y.MemberType})}).ToArray();
But here - I get a compile error with following error message:
Error CS0746: Invalid anonymous type member declarator. Anonymous type
members must be declared with a member assignment, simple name or
member access.
So how can I achieve my goal? Any suggestions?
I tried to simulate your scenario and following solution will work for you.
public class PersonalList
{
public List<ListMember> ListMembers { get; set; }
public long ListNumber { get; set; }
public string Description { get; set; }
}
public class ListMember
{
public string MemberName { get; set; }
public long ListId { get; set; }
public string MemberType { get; set; }
public string Position { get; set; }
}
static void Main(string[] args)
{
List<PersonalList> _allPersonalLists = new List<PersonalList>();
for (int i = 1; i <= 5; i++)
{
List<ListMember> ListMembers = new List<ListMember>();
for (int j = 1; j <= 3; j++)
ListMembers.Add(new ListMember() { ListId = j, MemberName = "Member" + i + j, MemberType = "Type" + i, Position = "Position" + i });
_allPersonalLists.Add(new PersonalList() { ListNumber = i, ListMembers = ListMembers, Description = "Desc" + i });
}
var personalLists = _allPersonalLists.ToDictionary(x => x.ListNumber, x => x.ListMembers.Select(y => new { y.MemberName, y.MemberType }).ToList());
Console.ReadLine();
}
var personalLists = _allPersonalLists
.Select(x => new
{
x.ListNumber,
members = x.ListMembers
.Select(y => new
{
y.MemberName,
y.MemberType
}).ToList()
}).ToArray();
`.ToList()` i included to keep actual values otherwise it will be enumerable

Load the xml file into array of custom class

I have a xml file with 200 of the following data
<Dices>
<Dice>
<Sequence>1</Sequence>
<Dice1>2</Dice1>
<Dice2>2</Dice2>
</Dice>
<Dice>
<Sequence>2</Sequence>
<Dice1>3</Dice1>
<Dice2>4</Dice2>
</Dice>
and in my main program, I have a class of "Dice"
int _sequence, _dice1, _dice2
public Dice(sequence, dice1, dice2) ......
public int sequence { get { return _sequence; } set { _sequence = value; } }
public int dice1 { get { return _dice1; } set { _dice1 = value; } }
public int dice2 { get { return _dice2; } set { _dice2 = value; } }
How do I load the xml into an array of Dice class?
Thanks!
Oops, I forgot to include my own code
I thought this would work, but apparently it returns null for all
Please take a look for me?
Dice[] load_dices = (from dice in load_xml.Elements("Dice")
select new Dice
{
sequence = (int)dice.Element("Sequence"),
dice1 = (int)dice.Element("Dice1"),
dice2 = (int)dice.Element("Dice2")
})
.ToArray();
Use System.Xml.Serialization attributes
using System.Xml.Serialization;
using System.Collections.Generic;
[XmlRoot("dices")]
public class DicesElement
{
[XmlArray("dice")]
[XmlArrayItem("dice", Type = typeof(DiceElement))]
public List<DiceElement> Dice { get; set;}
}
...
using System.Xml.Serialization;
public class DiceElement
{
[XmlElement("Sequence")]
public string Sequence { get; set; }
[XmlElement("Dice1")]
public string Dice1{ get; set; }
[XmlElement("Dice2")]
public string Dice2{ get; set; }
}
Then you can deserialize them and the heavy lifting is done.
More info on deserializing: https://blog.udemy.com/csharp-serialize-to-xml/
You must first select the root element
public class Program
{
public static void Main(string[] args)
{
string xml = #"<Dices>
<Dice>
<Sequence>1</Sequence>
<Dice1>2</Dice1>
<Dice2>2</Dice2>
</Dice>
<Dice>
<Sequence>2</Sequence>
<Dice1>3</Dice1>
<Dice2>4</Dice2>
</Dice></Dices>";
XDocument xd = XDocument.Parse(xml);
Dice[] load_dices = (from dice in xd.Root.Elements("Dice")
select new Dice
{
Sequence = (int)dice.Element("Sequence"),
Dice1 = (int)dice.Element("Dice1"),
Dice2 = (int)dice.Element("Dice2")
}).ToArray();
foreach (var x in load_dices)
Console.WriteLine(x);
}
}
public class Dice
{
public int Sequence { get; set; }
public int Dice1 { get; set; }
public int Dice2 { get; set; }
public override string ToString()
{
return string.Format("{0}\t{1}\t{2}", Sequence, Dice1, Dice2);
}
}
Print:
1 2 2
2 3 4
Link: http://rextester.com/IFABI55474
Another part that might help is you must use the default namespace when attempting to find items.
var xDoc = XDocument.Load(fileInfo.FullName, LoadOptions.PreserveWhitespace);
var defaultNs = xDoc.Root.GetDefaultNamespace();
var packageElement = xDoc.Descendants(defaultNs + "package")
.Where(n => string.IsNullOrWhiteSpace(n.Attribute("id").Value) == false
&& n.Attribute("id").Value.Equals("SomeValue", StringComparison.CurrentCultureIgnoreCase)
&& n.Attribute("version").Value.Equals("1.1.2") == false)
.SingleOrDefault();
Without adding the default namespace value to the Descendants method it would not find anything. I'm not sure that this is necessarily your problem but I just wanted to provide this information for you as well.

Compare properties of two objects fast c#

I have two objects of same type with different values:
public class Itemi
{
public Itemi()
{
}
public int Prop1Min { get; set; }
public int Prop1Max { get; set; }
public int Prop2Min { get; set; }
public int Prop2Max { get; set; }
public int Prop3Min { get; set; }
public int Prop3Max { get; set; }
...................................
public int Prop25Min { get; set; }
public int Prop25Max { get; set; }
}
Now I instantiate two objects of this type and add some values to their properties.
Itemi myItem1 = new Itemi();
myItem1.Prop1Min = 1;
myItem1.Prop1Max = 4;
myItem1.Prop2Min = 2;
myItem1.Prop2Max = 4;
myItem1.Prop3Min = -1;
myItem1.Prop3Max = 5;
.............................
myItem1.Prop25Min = 1;
myItem1.Prop25Max = 5;
Itemi myItem2 = new Itemi();
myItem2.Prop1Min = 1;
myItem2.Prop1Max = 5;
myItem2.Prop2Min = -10;
myItem2.Prop2Max = 3;
myItem2.Prop3Min = 0;
myItem2.Prop3Max = 2;
................................
myItem2.Prop25Min = 3;
myItem2.Prop25Max = 6;
What is the best and fastest way to do this comparison:
take each properties from myItem1 and check if values from Prop1-25 Min and Max are within the range values of myItem2 Prop1-25 Min and Max
Example:
myItem1.Prop1Min = 1
myItem1.Prop1Max = 4
myItem2.Prop1Min = 1
myItem2.Prop1Max = 5
this is True because mtItem1 Prop1 min and max are within the range of myItem2 min and max.
the condition should be AND in between all properties so in the end after we check all 25 properties if all of them are within the range of the second object we return true.
Is there a fast way to do this using Linq or other algorithm except the traditional if-else?
I would refactor the properties to be more along the lines of:
public class Item
{
public List<Range> Ranges { get; set; }
}
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
}
Then your comparison method could be:
if (myItem1.Ranges.Count != myItem2.Ranges.Count)
{
return false;
}
for (int i = 0; i < myItem1.Ranges.Count; i++)
{
if (myItem1.Ranges[i].Min < myItem2.Ranges[i].Min ||
myItem1.Ranges[i].Max > myItem2.Ranges[i].Max)
{
return false;
}
}
return true;
Otherwise you will have to use Reflection, which is anything but fast.
Linq is using standart statements like if...then, for each and other, there is no magic :)
If the final goal only to compare, without needing to say, which properties are not in the range, then you not need to check them all, on the first unequals you can end checking.
Because you have so much properties, you must think about saving it in Dictionary, or List, for example. Or to use dynamic properties (ITypedList), if it will use for binding.
You really should do something like Ginosaji proposed.
But if you want to go with your current data model, here is how I would solve it. Happy typing. :)
public static bool RangeIsContained(int outerMin, int outerMax, int innerMin, int innerMax)
{
return (outerMin <= innerMin && outerMax >= innerMax);
}
public bool IsContained(Itemi outer, Itemi inner)
{
return RangeIsContained(outer.Prop1Min, outer.Prop1Max, inner.Prop1Min, inner.Prop1Max)
&& RangeIsContained(outer.Prop2Min, outer.Prop2Max, inner.Prop2Min, inner.Prop2Max)
// ...
&& RangeIsContained(outer.Prop25Min, outer.Prop25Max, inner.Prop25Min, inner.Prop25Max);
}
With your data model this is basically the only way to go except for reflection (slow!). LINQ cannot help you because your data is not enumerable.
For the sake of completeness, here is a LINQ solution (but it's less performant and less readable than Ginosaji's solution!)
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
public static bool IsContained(Range super, Range sub)
{
return super.Min <= sub.Min
&& super.Max >= sub.Max;
}
}
public class Itemi
{
public Itemi()
{
properties = new Range[25];
for (int i = 0; i < properties.Length; i++)
{
properties[i] = new Range();
}
}
private Range[] properties;
public IEnumerable<Range> Properties { get { return properties; } }
public static bool IsContained(Itemi super, Itemi sub)
{
return super.properties
.Zip(sub.properties, (first, second) => Tuple.Create(first, second))
.All((entry) => Range.IsContained(entry.Item1, entry.Item2));
}
public Range Prop1
{
get { return properties[0]; }
set { properties[0] = value; }
}
public Range Prop2
{
get { return properties[1]; }
set { properties[1] = value; }
}
// ...
}

select child object collection with lambdas

I have the following class objects:
public class VacancyCategory
{
public int ID { get; set; }
public string Text { get; set; }
public IList<VacancySubCategory> SubCategories { get; set; }
}
public class VacancySubCategory
{
public int ID { get; set; }
public string Text { get; set; }
public VacancyCategory Category { get; set; }
public IList<Vacancy> Vacancies { get; set; }
}
public class Vacancy : IBusinessObject
{
public int ID { get; set; }
public string Title { get; set; }
public VacancySubCategory SubCategory { get; set; }
public string Body { get; set; }
public VacancyWorkType WorkType { get; set; }
public string Salary { get; set; }
public DateTime? AppsClosingDate { get; set; }
public bool Active { get; set; }
}
...so in a test repository im creating test data like so:
private IList<VacancyCategory> GetVacancyCategoriesWithAllChildCollections()
{
IList<VacancyCategory> vacancyCategories = new List<VacancyCategory>();
int cCounter = 0;
int scCounter = 0;
int vCounter = 0;
for (int i = 1; i <= 3; i++)
{
VacancyCategory vc = new VacancyCategory();
vc.ID = ++cCounter;
vc.Text = "VacancyCategory" + i.ToString();
for (int j = 1; j <= 3; j++)
{
VacancySubCategory vsc = new VacancySubCategory();
vsc.ID = ++scCounter;
vsc.Text = "VacancySubCategory" + scCounter.ToString();
vsc.Category = vc;
for (int k = 1; k <= 2; k++)
{
Vacancy v = new Vacancy();
v.ID = ++vCounter;
v.Title = "Vacancy" + vCounter.ToString();
v.Body = "VacancyBody" + vCounter.ToString();
v.Active = vCounter >= 16 ? false : true;
v.WorkType = this._workTypes.Single(wt => wt.ID == k);
v.Salary = vCounter <= 7 ? "SR " + (vCounter * 1000).ToString() : "";
v.AppsClosingDate = (vCounter >= 3 & vCounter <= 13) ? (new DateTime(2009, 3, vCounter)) : (DateTime?)null;
v.SubCategory = vsc;
if (vsc.Vacancies == null)
vsc.Vacancies = new List<Vacancy>();
vsc.Vacancies.Add(v);
}
if (vc.SubCategories == null)
vc.SubCategories = new List<VacancySubCategory>();
vc.SubCategories.Add(vsc);
}
vacancyCategories.Add(vc);
}
return vacancyCategories;
}
..so now i have some good test data. the object tree / chained objects are important to me.
so i'd like to return the individual object collections from this tree when desired. for example, if i wanted the whole tree, i can just return the VacancyCategory list with all the child objects - great. but now i want to return just the VacancySubCaregory items (all 9 of them). this would be my public method to the test repository:
public IQueryable<VacancySubCategory> GetVacancySubCategories()
{
throw new NotImplementedException("write gen code");
}
.. obviously without the exception. i have a member field called _categories that contains the results from the GetVacancyCategoriesWithAllChildCollections method. so i've been trying stuff like
this._categories.Select( ......
..but i cant seem to return a list of VacancySubCategory objects. i seem to always be selecting the root collection (ie. a result set of VacancyCategory objects). What am i doing wrong? im sure its simple... but its driving me nuts!
EDIT
thanx matt.
your suggestion led me to this:
public IQueryable<VacancySubCategory> GetVacancySubCategories()
{
return this._categories.SelectMany(c => c.SubCategories).AsQueryable<VacancySubCategory>();
}
..which works great. you're a champ
Try:
return this._categories.SelectMany(c => c.SubCategories);
This should work.
var query = from vc in GetVacancyCategoriesWithAllChildCollections()
from vcs in vc.SubCategories
select vcs

Categories