I am having some trouble in querying an object array using LINQ. I want to retrieve all products that contains the value passed.
My Product class
public class Product
{
public int mProductId;
public string mProductName;
public string mProductColor;
public string mProductSize;
public string mProductStatus;
public string mProductCode;
public int ProductId{ get { return mProductId; }}
public string ProductName { get{return mProductName; }}
public string ProductColor { get{return mProductColor;} }
public string ProductSize { get{return mProductSize;} }
public string ProductStatus { get{return mProductStatus;} }
public string ProductCode {get { return mProductCode; }}
}
public class ProductList
{
public static Product[] mProductList = {
new Product { mProductId = Resource.Drawable.Product1,
mProductName = "Green Lumberjack Cap",
mProductColor = "Color Brown",
mProductSize = "One Size Fits All",
mProductCode= "9780201760439",
mProductStatus= "In Stock"},
new Product { mProductId = Resource.Drawable.Product2,
mProductName = "Square Bar stool",
mProductColor= "Color Brown",
mProductSize = "One Size Fits All",
mProductCode= "9780201760440",
mProductStatus= "In Stock"},
new Product { mProductId = Resource.Drawable.Product3,
mProductName = "Vitra bathroom Tile",
mProductColor= "Color Brown",
mProductSize = "One Size Fits All",
mProductCode= "9780201760539",
mProductStatus= "In Stock"},
};
private Product[] mProducts;
Random mRandom;
public ProductList ()
{
mProducts = mProductList;
}
// Return the number of photos in the photo album:
public int NumPhotos
{
get { return mProducts.Length; }
}
// Indexer (read only) for accessing a photo:
public Product this[int i]
{
get { return mProducts[i]; }
}
// Pick a random photo and swap it with the top:
public int RandomSwap()
{
// Save the photo at the top:
Product tmpProduct = mProducts[0];
// Generate a next random index between 1 and
// Length (noninclusive):
int rnd = mRandom.Next(1, mProducts.Length);
// Exchange top photo with randomly-chosen photo:
mProducts[0] = mProducts[rnd];
mProducts[rnd] = tmpProduct;
// Return the index of which photo was swapped with the top:
return rnd;
}
// Shuffle the order of the photos:
public void Shuffle ()
{
// Use the Fisher-Yates shuffle algorithm:
for (int idx = 0; idx < mProducts.Length; ++idx)
{
// Save the photo at idx:
Product tmpProduct = mProducts[idx];
// Generate a next random index between idx (inclusive) and
// Length (noninclusive):
int rnd = mRandom.Next(idx, mProducts.Length);
// Exchange photo at idx with randomly-chosen (later) photo:
mProducts[idx] = mProducts[rnd];
mProducts[rnd] = tmpProduct;
}
}
}
and my LINQ statement is
var result = from p in nProductList<Product>
where ( p.mProductName.Contains(query) || p.mProductColor.Contains(query))
select p;
I have also declared nProductList in my class as
public ProductList nProductList;
It will be really great to know what am I doing wrong.
Thank you
In order to get the where keyword syntax to work, your ProductList class must have a Where(Func<Product, bool>) method on it. Most lists get this automatically because they implement IEnumerable<>, and the System.Linq namespace has a Where() extension method which matches this signature.
You could make ProductList implement the IEnumerable<Product> interface, or make it extend a class like List<Product> which already implements that interface, or add your own Where() method. However, I'd personally suggest that you just expose mProductList as an IEnumerable<Product> via a public property getter, and change your consuming code to query against that.
The reason why your linq statement does not work is because you did not define where. Imagine the old style linq:
nProductList.Where(p=>p.mProductName.Contains(query) || p.mProductColor.Contains(query)).Select(p=>);
nProductList does not have Where(Func) defined so it does not work.
Normally for your ProductList there are two ways to implement. First way is to inherit from IEnumerable<Product> as ProductList : IEnumerable<Product>;
Second way is to create a member in ProductList and make it public like
public class ProductList
{
public IEnumerable<Product> Products {get; private set;}
...
}
Usually the preferable way between the two above will depends on is there more properties or more methods in your ProductList class. More methods goes to the first way because it's more like an expended method collection of IEnumerable class (like your example), while more properties goes to the seconding way as this is more like another class just having a list in it and something else.
Related
I have two arrays of ArrayList.
public class ProductDetails
{
public string id;
public string description;
public float rate;
}
ArrayList products1 = new ArrayList();
ArrayList products2 = new ArrayList();
ArrayList duplicateProducts = new ArrayList();
Now what I want is to get all the products (with all the fields of ProductDetails class) having duplicate description in both products1 and products2.
I can run two for/while loops as traditional way, but that would be very slow specially if I will be having over 10k elements in both arrays.
So probably something can be done with LINQ.
If you want to use linQ, you need write your own EqualityComparer where you override both methods Equals and GetHashCode()
public class ProductDetails
{
public string id {get; set;}
public string description {get; set;}
public float rate {get; set;}
}
public class ProductComparer : IEqualityComparer<ProductDetails>
{
public bool Equals(ProductDetails x, ProductDetails y)
{
//Check whether the objects are the same object.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether the products' properties are equal.
return x != null && y != null && x.id.Equals(y.id) && x.description.Equals(y.description);
}
public int GetHashCode(ProductDetails obj)
{
//Get hash code for the description field if it is not null.
int hashProductDesc = obj.description == null ? 0 : obj.description.GetHashCode();
//Get hash code for the idfield.
int hashProductId = obj.id.GetHashCode();
//Calculate the hash code for the product.
return hashProductDesc ^ hashProductId ;
}
}
Now, supposing you have this objects:
ProductDetails [] items1= { new ProductDetails { description= "aa", id= 9, rating=2.0f },
new ProductDetails { description= "b", id= 4, rating=2.0f} };
ProductDetails [] items= { new ProductDetails { description= "aa", id= 9, rating=1.0f },
new ProductDetails { description= "c", id= 12, rating=2.0f } };
IEnumerable<ProductDetails> duplicates =
items1.Intersect(items2, new ProductComparer());
Consider overriding the System.Object.Equals method.
public class ProductDetails
{
public string id;
public string description;
public float rate;
public override bool Equals(object obj)
{
if(obj is ProductDetails == null)
return false;
if(ReferenceEquals(obj,this))
return true;
ProductDetails p = (ProductDetails)obj;
return description == p.description;
}
}
Filtering would then be as simple as:
var result = products1.Where(product=>products2.Contains(product));
EDIT:
Do consider that this implementation is not optimal..
Moreover- it has been proposed in the comments to your question that you use a data base.
This way performance will be optimized - as per the database implementation In any case- the overhead will not be yours.
However, you can optimize this code by using a Dictionary or a HashSet:
Overload the System.Object.GetHashCode method:
public override int GetHashCode()
{
return description.GetHashCode();
}
You can now do this:
var hashSet = new HashSet<ProductDetails>(products1);
var result = products2.Where(product=>hashSet.Contains(product));
Which will boost your performance to an extent since lookup will be less costly.
10k elements is nothing, however make sure you use proper collection types. ArrayList is long deprecated, use List<ProductDetails>.
Next step is implementing proper Equals and GetHashCode overrides for your class. The assumption here is that description is the key since that's what you care about from a duplication point of view:
public class ProductDetails
{
public string id;
public string description;
public float rate;
public override bool Equals(object obj)
{
var p = obj as ProductDetails;
return ReferenceEquals(p, null) ? false : description == obj.description;
}
public override int GetHashCode() => description.GetHashCode();
}
Now we have options. One easy and efficient way of doing this is using a hash set:
var set = new HashSet<ProductDetails>();
var products1 = new List<ProductDetails>(); // fill it
var products2 = new List<ProductDetails>(); // fill it
// shove everything in the first list in the set
foreach(var item in products1)
set.Add(item);
// and simply test the elements in the second set
foreach(var item in products2)
if(set.Contains(item))
{
// item.description was already used in products1, handle it here
}
This gives you linear (O(n)) time-complexity, best you can get.
I have the following:
public class Broadcast {
public int NumUsersToMessage { get; set; }
public int NumMessagesQueued { get; set; }
public string DbUsersMessaged { get; set; }
public int NumMessagesSent {
get {
return UsersMessaged.Count();
}
}
public List<int> UsersMessaged {
get {
return DbUsersMessaged == null ? new List<int>() : DbUsersMessaged.Split(',').Select(Int32.Parse).ToList();
}
set {
DbUsersMessaged = value != null ? String.Join(",", value) : null;
}
}
}
My goal here is to only ever access DbUsersMessaged through UsersMessaged. I'm attempting to do broadcast.UsersMessaged.Add(2), however since this is not an assignment, I can't get the property to behave as I like. Instead, I have to do this:
tempList = broadcast.UsersMessaged();
tempList.Add(2);
broadcast.UsersMessaged = tempList;
db.SaveChanges();
Which is obviously unwieldy. I'm considering making an AddReassign extension method but I want to know - what's the standard practice here for supporting Lists of primitive types? It looks like even with the extension method, my best shot looks like this:
broadcast.UsersMessaged = broadcast.UsersMessaged.AddReassign(2) // yuck!
Before anyone asks - we've intentionally denormalized this for performance reasons.
If you don't care about performance, you can create own list:
public class MyList : IList<int>
{
private List<int> underlyingList;
private Broadcast entity;
public MyList(Broadcast entity)
{
this.entity = entity;
this.underlyingList = entity.DbUsersMessaged?.Split(",") ?? new List<int>();
}
public void Add(int i)
{
this.underlyingList.Add(i);
this.entity.DbUsersMessaged = String.Join(",", underylingList);
}
// other interface memebers impl
}
Then
MyList list;
public IList<int> UsersMessaged {
get {
return myList ?? (myList = new MyList(this));
}
}
Of course it is only sample.
I recommend you to have a look at this: Entity Framework 5 - Looking for Central Point to Execute Custom Code after Entity is Loaded from Database
And then convert from string to list, and then use Saving Changes event to convert back into the string construction when saving.
Then, for performance, maybe you want to use byte[] rather than a string for storing the data in the database.
I want to add row number in object list.
here's the they i do it now but there must be better way
Profile for mapping
public class VendorEnquiryDM_TO_VM : Profile
{
public VendorEnquiryDM_TO_VM()
{
CreateMap<VENDORENQUIRY, VendorEnquiryVM>();
}
}
public class VendorEnquiryVM_TO_DM : Profile
{
public VendorEnquiryVM_TO_DM()
{
CreateMap<VENDOR_ENQUIRY, VendorEnquiryVM>().ReverseMap();
}
}
Register profile
cfg.AddProfile<VendorEnquiryDM_TO_VM>();
cfg.AddProfile<VendorEnquiryVM_TO_DM>();
This is how I add sno.
alldata = Mapper.Map<IEnumerable<Vendor_EnquiryVM>>(objDAO.getVendorEnquiry());
var _roles = alldata.Select((t, index) => new Vendor_EnquiryVM
{
sno = index + 1,
CONTACT_NO=t.CONTACT_NO,
DATE=t.DATE,
EMAIL=t.EMAIL,
id=t.id,
FIRST_NAME=t.FIRST_NAME,
wer=t.wer,
asdf=t.asdf
});
Due to just one serial no. I need to assign all properties and this is somewhat fraustrating to me for large model, please suggest me better way of doing this.
You can define a static Id and when you create the class, increment it by one
here how your class code should look like
public class Test
{
private static int mId = 0;
public Test()
{
mId = mId +1;
}
public int Id
{
get{ return mId;}
}
}
Here a demo
in order to use the same idea with collections like List, I applied some modifications and here what you can do
public class Test
{
private static int mIndex = 0; // this parameter will be incremented for each new Test
private int mId =0; // this parameter will hold the last incremented value
public Test()
{
mId = ++mIndex; // mIndex++ if you want to start with 0
}
public int Id
{
get{ return mId;}
}
}
Demo with lists
hope this will help you
I have been given some code that has objects composed of lists of different types. A simple example of what I mean:
public class Account
{
private long accountID;
private List<string> accountHolders;
private List<string> phoneNumbers;
private List<string> addresses;
public Account()
{
this.accountHolders = new List<string>();
this.phoneNumbers = new List<string>();
this.addresses = new List<string>();
}
public long AccountID
{
get
{
return this.accountID;
}
set
{
this.accountID = value;
}
}
}
For a requirement I need to get the total amount of elements in each list for validation purposes. I have the following method which works:
public class AccountParser
{
// Some code
public int CountElements(Account acct)
{
int count = 0;
count += acct.accountHolders.Count();
count += acct.phoneNumbers.Count();
count += acct.addresses.Count();
return count;
}
}
but was wondering if there was a better way to do this. I know I can enumerate over a List with Linq but I can't seem to get it to work in this case.
What you're doing is the right thing
You could do it in one line without declaring any variable
public int CountElements(Account acct)
{
return acct.accountHolders.Count() + acct.phoneNumbers.Count() + acct.addresses.Count();
}
But it doesn't change much.
The ammount of lists is static, because the class is static, so it doesn't make sense to use Reflection if the structure wont change.
Now you could have more than one Account classes with different types of lists. In that case, i would create an abstract AbsAccount class, that has an abstract CountElements property:
public abstract class AbsAccount
{
public abstract int CountElements { get; }
}
public class Account: AbsAccount
{
private List<string> accountHolders;
private List<string> phoneNumbers;
private List<string> addresses;
public override int CountElements
{
get
{
return this.accountHolders.Count()
+ this.phoneNumbers.Count()
+ this.addresses.Count();
}
}
}
public class AccountParser
{
// Some code
public int CountElements(AbsAccount acct)
{
return acct.CountElements;
}
}
But maybe im taking it too far...
You can add items to a list then call .Summethod on it, but it's not better from performance point of view.
public class AccountParser
{
// Some code
public int CountElements(Account acct)
{
List<string> all = new List<string>();
all.AddRange(acct.accountHolders);
all.AddRange(acct.phoneNumbers);
all.AddRange(acct.addresses);
return all.Count();
}
}
Another approach will be (because I can see you are not exposing directly your lists) to use observer pattern, and update the number of elements in another field or even list, every time you are updating one of your lists. Then get the value from that field, but I think the best way is the one you have already adopted.
This is all in C#, using .NET 2.0.
I have two lists of objects. They are not related objects, but they do have certain things in common that can be compared, such as a GUID-based unique identifier. These two lists need to be filtered by another list which just contains GUIDs which may or may not match up with the IDs contained in the first two lists.
I have thought about the idea of casting each object list to just object and sorting by that, but I'm not sure that I'll be able to access the ID property once it's cast, and I'm thinking that the method to sort the two lists should be somewhat dumb in knowing what the list to be sorted is.
What would be the best way to bring in each object list so that it can be sorted against the list with only the IDs?
You should make each of your different objects implement a common interface. Then create an IComparer<T> for that interface and use it in your sort.
Okay, if you have access to modify your original classes only to add the interface there, Matthew had it spot on. I went a little crazy here and defined out a full solution using 2.0 anonymous delegates. (I think I'm way addicted to 3.0 Lambda; otherwise, I probably would've written this out in foreach loops if I was using 2005 still).
Basically, create an interface with the common properties. Make yoru two classes implement the interface. Create a common list casted as the interface, cast and rip the values into the new list; remove any unmatched items.
//Program Output:
List1:
206aa77c-8259-428b-a4a0-0e005d8b016c
64f71cc9-596d-4cb8-9eb3-35da3b96f583
List2:
10382452-a7fe-4307-ae4c-41580dc69146
97f3f3f6-6e64-4109-9737-cb72280bc112
64f71cc9-596d-4cb8-9eb3-35da3b96f583
Matches:
64f71cc9-596d-4cb8-9eb3-35da3b96f583
Press any key to continue . . .
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
//test initialization
List<ClassTypeA> list1 = new List<ClassTypeA>();
List<ClassTypeB> list2 = new List<ClassTypeB>();
ClassTypeA citem = new ClassTypeA();
ClassTypeB citem2 = new ClassTypeB();
citem2.ID = citem.ID;
list1.Add(new ClassTypeA());
list1.Add(citem);
list2.Add(new ClassTypeB());
list2.Add(new ClassTypeB());
list2.Add(citem2);
//new common list.
List<ICommonTypeMakeUpYourOwnName> common_list =
new List<ICommonTypeMakeUpYourOwnName>();
//in english, give me everything in list 1
//and cast it to the interface
common_list.AddRange(
list1.ConvertAll<ICommonTypeMakeUpYourOwnName>(delegate(
ClassTypeA x) { return (ICommonTypeMakeUpYourOwnName)x; }));
//in english, give me all the items in the
//common list that don't exist in list2 and remove them.
common_list.RemoveAll(delegate(ICommonTypeMakeUpYourOwnName x)
{ return list2.Find(delegate(ClassTypeB y)
{return y.ID == x.ID;}) == null; });
//show list1
Console.WriteLine("List1:");
foreach (ClassTypeA item in list1)
{
Console.WriteLine(item.ID);
}
//show list2
Console.WriteLine("\nList2:");
foreach (ClassTypeB item in list2)
{
Console.WriteLine(item.ID);
}
//show the common items
Console.WriteLine("\nMatches:");
foreach (ICommonTypeMakeUpYourOwnName item in common_list)
{
Console.WriteLine(item.ID);
}
}
}
interface ICommonTypeMakeUpYourOwnName
{
Guid ID { get; set; }
}
class ClassTypeA : ICommonTypeMakeUpYourOwnName
{
Guid _ID;
public Guid ID {get { return _ID; } set { _ID = value;}}
int _Stuff1;
public int Stuff1 {get { return _Stuff1; } set { _Stuff1 = value;}}
string _Stuff2;
public string Stuff2 {get { return _Stuff2; } set { _Stuff2 = value;}}
public ClassTypeA()
{
this.ID = Guid.NewGuid();
}
}
class ClassTypeB : ICommonTypeMakeUpYourOwnName
{
Guid _ID;
public Guid ID {get { return _ID; } set { _ID = value;}}
int _Stuff3;
public int Stuff3 {get { return _Stuff3; } set { _Stuff3 = value;}}
string _Stuff4;
public string Stuff4 {get { return _Stuff4; } set { _Stuff4 = value;}}
public ClassTypeB()
{
this.ID = Guid.NewGuid();
}
}
}
Using only .NET 2.0 methods:
class Foo
{
public Guid Guid { get; }
}
List<Foo> GetFooSubset(List<Foo> foos, List<Guid> guids)
{
return foos.FindAll(foo => guids.Contains(foo.Guid));
}
If your classes don't implement a common interface, you'll have to implement GetFooSubset for each type individually.
I'm not sure that I fully understand what you want, but you can use linq to select out the matching items from the lists as well as sorting them. Here is a simple example where the values from one list are filtered on another and sorted.
List<int> itemList = new List<int>() { 9,6,3,4,5,2,7,8,1 };
List<int> filterList = new List<int>() { 2, 6, 9 };
IEnumerable<int> filtered = itemList.SelectMany(item => filterList.Where(filter => filter == item)).OrderBy(p => p);
I haven't had a chance to use AutoMapper yet, but from what you describe you wish to check it out. From Jimmy Bogard's post:
AutoMapper conventions
Since AutoMapper flattens, it will
look for:
Matching property names
Nested property names (Product.Name
maps to ProductName, by assuming a
PascalCase naming convention)
Methods starting with the word “Get”,
so GetTotal() maps to Total
Any existing type map already
configured
Basically, if you removed all the
“dots” and “Gets”, AutoMapper will
match property names. Right now,
AutoMapper does not fail on mismatched
types, but for some other reasons.
I am not totally sure what you want as your end results, however....
If you are comparing the properties on two different types you could project the property names and corresponding values into two dictionaries. And with that information do some sort of sorting/difference of the property values.
Guid newGuid = Guid.NewGuid();
var classA = new ClassA{Id = newGuid};
var classB = new ClassB{Id = newGuid};
PropertyInfo[] classAProperties = classA.GetType().GetProperties();
Dictionary<string, object> classAPropertyValue = classAProperties.ToDictionary(pName => pName.Name,
pValue =>
pValue.GetValue(classA, null));
PropertyInfo[] classBProperties = classB.GetType().GetProperties();
Dictionary<string, object> classBPropetyValue = classBProperties.ToDictionary(pName => pName.Name,
pValue =>
pValue.GetValue(classB, null));
internal class ClassB
{
public Guid Id { get; set; }
}
internal class ClassA
{
public Guid Id { get; set; }
}
classAPropertyValue
Count = 1
[0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}
classBPropetyValue
Count = 1
[0]: {[Id, d0093d33-a59b-4537-bde9-67db324cf7f6]}
Thist should essentially get you what you want - but you may be better of using linq
class T1
{
public T1(Guid g, string n) { Guid = g; MyName = n; }
public Guid Guid { get; set; }
public string MyName { get; set; }
}
class T2
{
public T2(Guid g, string n) { ID = g; Name = n; }
public Guid ID { get; set; }
public string Name { get; set; }
}
class Test
{
public void Run()
{
Guid G1 = Guid.NewGuid();
Guid G2 = Guid.NewGuid();
Guid G3 = Guid.NewGuid();
List<T1> t1s = new List<T1>() {
new T1(G1, "one"),
new T1(G2, "two"),
new T1(G3, "three")
};
List<Guid> filter = new List<Guid>() { G2, G3};
List<T1> filteredValues1 = t1s.FindAll(delegate(T1 item)
{
return filter.Contains(item.Guid);
});
List<T1> filteredValues2 = t1s.FindAll(o1 => filter.Contains(o1.Guid));
}
}