Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to compare a value and a value of an object in a list...
and be able to use it with others object type lists.
like :
ID = generateID();
CheckUsableID(ID, TeamList);
// or CheckUsableID(ID, PlayerList);
Please help me !
// C# Code
public bool CheckUsableID(int id, List<object> list)
{
foreach(var object in list)
{
if (list<object>.id == id)
{
return false;
}
}
return true;
}
I just want to compare them.
In order to check lists of different types you'll need something either an interface or base class that all the objects that could appear in a list implement. When you have that you can use generics when defining the method.
For example, we could define an interface:
public interface IDomainObject
{
int id { get; set; }
}
Then we can redefine the method with generics:
public bool CheckUsableID<T>(int id, List<T> list) where T : IDomainObject
{
foreach(var item in list)
{
if (item.id == id)
{
return false;
}
}
return true;
}
Assuming that TeamList is a List<Team> or similar and PlayerList is a List<Player> or similar you will need to just ensure Team and Player implement the IDomainObject interface and you'll be able to pass them to the CheckUsableID method:
List<Team> TeamList = new List<Team>();
//populate TeamList from somewhere
ID = generateID();
CheckUsableID(ID, TeamList);
If you create a base class you could then put the method in the base class:
Why not use LINQ? There's no need to loop through the entire list. Let Linq do the dirty work for you.
bool hasUsableID = TeamList.Any(t => t.Id == ID);
bool hasUsableID = PlayerList.Any(p => p.Id == ID);
I'm assuming
TeamList is a List< Team > and Team has the property ID exposed
PlayerList is a List< Player > and Player has the property ID exposed
You need to use reflection. Here you go with your modified sample !
// C# Code
public bool CheckUsableID(int id, List<object> list)
{
foreach (var obj in list)
{
var objId = (int)GetValueFromObj(obj, "id");
if (objId == id)
{
return false;
}
}
return true;
}
private object GetValueFromObj(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj);
}
First off, you have plenty of syntax errors and improper use of the key words. I will provide you with an example and you can fix it yourself:
In this case, I'm assuming <object> is actually a class, right? In that case, you need to redefine the object.
public bool CheckUsableID(int id, List<clsSomeObject> someTeamList)
{
clsSomeObject newObject = new clsSomeObject();
newObject = someTeamList;
foreach(var object in newObject)
{
if (newObject.id == id)
{
return false;
}
}
return true;
}
Try something like this:
you Post a list of ID's that you whant to compare, and GET a list with ID.
public List<SomeObject > CheckUsableID(int id, List<SomeObject > list)
{
var listUsableId = new List<SomeObject >();
foreach(var object in list)
{
if (object.Id == id)
{
listUsableID.add(object);
}
}
return listUsableId;
}
public class SomeObject
{
public int Id { get; set }
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 months ago.
Improve this question
Trying to convert Array of Objects to String using C#. Able to achieve the same using LINQ, however trying to make use of reusable functions which would accept array of Objects and return back string. Understand that generics must be used but it's been hard time understanding it. Thanks in advance!
public class HelloWorld {
public static void Main() {
Root root = new Root();
List<A> obj = new List<A>();
obj.Add(new A() { Code = "WAY"});
obj.Add(new A() { Code = "DOWN"});
obj.Add(new A() { Code = "WE"});
obj.Add(new A() { Code = "GO"});
root.A = obj;
string _Result = string.Join("-", root.A.Where(x => x.Code != "").Select(p => p.Code.ToString()).ToArray());
Console.WriteLine(_Result); //Expected OP: WAY-DOWN-WE-GO
Console.WriteLine(Utility.ToArray(root.A)); //System.Collections.Generic.List`1[A]
}
//Trying for much simpler Generic function here.
public class Utility{
public static string ToArray(IList<Object> obj){
foreach(var v in obj){
//generic function..
}
StringBuilder sb = new StringBuilder();
return sb.ToString();
}
}
}
public class Root
{
public List<A> A { get; set; }
public List<B> B { get; set; }
}
public class A
{
public string Code { get; set; }
}
public class B
{
public string Mode { get; set; }
}
If you're looking for a system that works without having to have your classes implement an interface (for objects you didn't create, for example), it's possible to use a Func<T, object> to select a specific property/field:
// IEnumerable is more generic over "lists" (sets, maps, etc)
// \/
public static string ToArray<T>(IEnumerable<T> obj, Func<T, object> func) {
return string.Join('-', obj.Select(func));
}
Usage example:
List<A> aObjects = new();
//add aObjects
List<B> bObjects = new();
//add bObjects
Console.WriteLine(Utilities.ToArray(aObjects, a => a.Code));
Console.WriteLine(Utilities.ToArray(bObjects, b => b.Mode));
Reference: How to join as a string a property of a class?
I actually asked a very similar question recently, but while the title mentioned classes, my content mostly referred to a tuple, and the (really great) answer reflected that. When I've tried to substitute a class in for the tuple, I get TargetParameterCountException: Parameter count mismatch. exception.
How can I get NHibernate to map to a Tuple or Class?
I have the following method to get a list of results from the database.
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
This generally works well. However, I've changed a method that calls the method above from.
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
Which works, to this (as I don't want to return the whole of FooBarResult, just certain columns on it).
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
And this is the class.
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
As mentioned earlier, when running the return crit.GetExecutableCriteria(InstanceSession).List<T>(); code I get a TargetParameterCountException: Parameter count mismatch. exception.
Is there any way I can make it return a list of my MyCustomClass?
I have not tested this, but you should use Transformers.AliasToBean take a look in to the aliases to let the transformer work:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
In this line:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
you will get the first, default constructor and its signature obviously doesn't match. The simplest fix for your case is:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
But the cleanest solution would be something along these lines (untested and also a bit simplified):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}
In my current project, a method I don't control sends me an object of this type:
public class SampleClass
{
public SampleClass();
public int ID { get; set; }
public List<SampleClass> Items { get; set; }
public string Name { get; set; }
public SampleType Type { get; set; }
}
public enum SampleType
{
type1,
type2,
type3
}
I display those data in a TreeView, but I would like to display only the path ending with SampleClass objects having their Type property set to type3, no matter the depth of this leaf.
I have absolutely no clue on how to do that, can someone help me ?
Thanks in advance !
Edit
To explain the problem I meet with the solutions proposed by Shahrooz Jefri and dasblinkenlight, here is a picture. The left column is the original data, without filtering, and the right one is the data filtered. Both methods provide the same result.
In red is the problem.
Use this Filter method:
public void Filter(List<SampleClass> items)
{
if (items != null)
{
List<SampleClass> itemsToRemove = new List<SampleClass>();
foreach (SampleClass item in items)
{
Filter(item.Items);
if (item.Items == null || item.Items.Count == 0)
if (item.Type != SampleType.type3)
itemsToRemove.Add(item);
}
foreach (SampleClass item in itemsToRemove)
{
items.Remove(item);
}
}
}
In addition to initially determining which items to show, if the datasize is substantial and you expect users to frequently collapse and expand sections then filtering after every click my result in slow ui response.
Consider the Decorator pattern or some other way of tagging each node with relevant info so that the filtering is not required after every click.
Try this approach:
static bool ShouldKeep(SampleClass item) {
return (item.Type == SampleType.type3 && item.Items.Count == 0)
|| item.Items.Any(ShouldKeep);
}
static SampleClass Filter(SampleClass item) {
if (!ShouldKeep(item)) return null;
return new SampleClass {
Id = item.Id
, Name = item.Name
, Type = item.Type
, Items = item.Items.Where(ShouldKeep).Select(x=>Filter(x)).ToList()
};
}
The above code assumes that Items of leaves are empty lists, rather than nulls.
I have a function that reads a file in chunks.
public static DataObject ReadNextFile(){ ...}
And dataobject looks like this:
public DataObject
{
public string Category { get; set; }
// And other members ...
}
What I want to do is the following basically
List<DataObject> dataObjects = new List<DataObject>();
while(ReadNextFile().Category == "category")
{
dataObjects.Add(^^^^^ the thingy in the while);
}
I know it's probably not how it's done, because how do I access the object I've just read.
I think what you're looking for is:
List<DataObject> dataObjects = new List<DataObject>();
DataObject nextObject;
while((nextObject = ReadNextFile()).Category == "category")
{
dataObjects.Add(nextObject);
}
But I wouldn't do that. I'd write:
List<DataObject> dataObject = source.ReadItems()
.TakeWhile(x => x.Category == "Category")
.ToList();
where ReadItems() was a method returning an IEnumerable<DataObject>, reading and yielding one item at a time. You may well want to implement it with an iterator block (yield return etc).
This is assuming you really want to stop reading as soon as you find the first object which has a different category. If you actually want to include all the matching DataObjects,
change TakeWhile to Where in the above LINQ query.
(EDIT: Saeed has since deleted his objections to the answer, but I guess I might as well leave the example up...)
EDIT: Proof that this will work, as Saeed doesn't seem to believe me:
using System;
using System.Collections.Generic;
public class DataObject
{
public string Category { get; set; }
public int Id { get; set; }
}
class Test
{
static int count = 0;
static DataObject ReadNextFile()
{
count++;
return new DataObject
{
Category = count <= 5 ? "yes" : "no",
Id = count
};
}
static void Main()
{
List<DataObject> dataObjects = new List<DataObject>();
DataObject nextObject;
while((nextObject = ReadNextFile()).Category == "yes")
{
dataObjects.Add(nextObject);
}
foreach (DataObject x in dataObjects)
{
Console.WriteLine("{0}: {1}", x.Id, x.Category);
}
}
}
Output:
1: yes
2: yes
3: yes
4: yes
5: yes
In other words, the list has retained references to the 5 distinct objects which have been returned from ReadNextFile.
This is subjective, but I hate this pattern (and I fully recognize that I am in the very small minority here). Here is how I do it when I need something like this.
var dataObjects = new List<DataObject>();
while(true) {
DataObject obj = ReadNextFile();
if(obj.Category != "category") {
break;
}
dataObjects.Add(obj);
}
But these days, it is better to say
List<DataObject> dataObjects = GetItemsFromFile(path)
.TakeWhile(x => x.Category == "category")
.ToList();
Here, of course, GetItemsFromFile reads the items from the file pointed to by path and returns an IEnumerable<DataObject>.
List<DataObject> dataObjects = new List<DataObject>();
string category = "";
while((category=ReadNextFile().Category) == "category")
{
dataObjects.Add(new DataObject{Category = category});
}
And if you have more complicated object you can do this (like jon):
List<DataObject> dataObjects = new List<DataObject>();
var category = new DataObject();
while((category=ReadNextFile()).Category == "category")
{
dataObjects.Add(category);
}
You should look into implementing IEnumerator on the class container the call to ReadNextFile(). Then you would always have reference to the current object with IEnumerator.Current, and MoveNext() will return the bool you are looking for to check for advancement. Something like this:
public class ObjectReader : IEnumerator<DataObject>
{
public bool MoveNext()
{
// try to read next file, return false if you can't
// if you can, set the Current to the returned DataObject
}
public DataObject Current
{
get;
private set;
}
}
I have an in-memory "table" that might looks something like this:
Favorite# Name Profession
--------- ---------- ------------------
3 Names.Adam Profession.Baker
9 Names.Bob Profession.Teacher
7 Names.Carl Profession.Coder
7 Names.Dave Profession.Miner
5 Names.Fred Profession.Teacher
And what I want to do, is do quick and efficient lookups, using any of the 3 fields.
In other words, I want:
myTable[3] and myTable[Names.Adam] and myTable[Professions.Baker] to all return {3,Names.Adam,Profession.Baker}
myTable[Profession.Teacher] to return both {9,Names.Bob,Profession.Teacher} and {5,Names.Fred,Profession.Teacher}.
The table is built during runtime, according to the actions of the user, and cannot be stored in a database since it is used in sections in which database connectivity cannot be guaranteed.
Right now, I "simply" (hah!) store this using 3 uber-Dictionaries, each keyed using one of the columns (FavoriteNumber, Name, Profession), and each value in the uber-Dictionaries holding 2 Dictionaries which are themselves keyed with each of the remaining columns (so the values in the "Name" uber-dictionary are of the type Dictionary<FavoriteNumber,Profession[]> and Dictionary<Profession, FavoriteNumber[]>
This requires 2 lookups in 2 Dictionaries, and another traverse of an array (which usually holds 1 or 2 elements.)
Can anyone suggest a better way to do this? I don't mind spending extra memory, since the table is likely to be small (no more than 20 entries) but I'm willing to sacrifice a little CPU to make it more readily maintainable code...
Not really however using a dictionary, but if you create a collection of classes like this
class Person {
public int FavoriteNumber;
public string Name;
public string Profession;
}
you can use LINQ to search the collections.
IList<Person> people = /* my collection */;
var selectedPeople = people.Where(p => p.FavoriteNumber = 3);
var selectedPeople2 = people.Where(p => p.Name == "Bob");
var selectedPeople3 = people.Where(p => p.Profession = "Teacher");
or if you prefer the normal LINQ syntax
var selectedPeople4 = from p in people
where p.Name == "Bob"
select p;
Each of these selectedPeople variables will be typed as IEnumerable<Person> and you can use a loop to search through them.
For 20 rows, just use linear scanning - it will be the most efficient in every way.
For larger sets; hzere's an approach using LINQ's ToLookup and delayed indexing:
public enum Profession {
Baker, Teacher, Coder, Miner
}
public class Record {
public int FavoriteNumber {get;set;}
public string Name {get;set;}
public Profession Profession {get;set;}
}
class Table : Collection<Record>
{
protected void Rebuild()
{
indexName = null;
indexNumber = null;
indexProfession = null;
}
protected override void ClearItems()
{
base.ClearItems();
Rebuild();
}
protected override void InsertItem(int index, Record item)
{
base.InsertItem(index, item);
Rebuild();
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
Rebuild();
}
protected override void SetItem(int index, Record item)
{
base.SetItem(index, item);
Rebuild();
}
ILookup<int, Record> indexNumber;
ILookup<string, Record> indexName;
ILookup<Profession, Record> indexProfession;
protected ILookup<int, Record> IndexNumber {
get {
if (indexNumber == null) indexNumber = this.ToLookup(x=>x.FavoriteNumber);
return indexNumber;
}
}
protected ILookup<string, Record> IndexName {
get {
if (indexName == null) indexName = this.ToLookup(x=>x.Name);
return indexName;
}
}
protected ILookup<Profession, Record> IndexProfession {
get {
if (indexProfession == null) indexProfession = this.ToLookup(x=>x.Profession);
return indexProfession;
}
}
public IEnumerable<Record> Find(int favoriteNumber) { return IndexNumber[favoriteNumber]; }
public IEnumerable<Record> Find(string name) { return IndexName[name]; }
public IEnumerable<Record> Find(Profession profession) { return IndexProfession[profession]; }
}
I think the way to do this is to write your own object that has
public ICollection<Record> this[int] { get; }
public ICollection<Record> this[Profession] { get; }
public ICollection<Record> this[Names] { get; }
where record is a class that holds your elements.
Internally, you keep a List and each indexer does List.FindAll() to get what you need.
Nothing out-of-the-box (except perhaps a DataTable). Nevertheless, it can be accomplished in a more simple way that what you've got:
Create a class to hold the data:
class PersonData {
public int FavoriteNumber;
public string Name;
public string Profession;
}
Then keep 3 dictionaries that point to the same reference:
PersonData personData = new PersonData();
Dictionary<int, PersonData> ...;
Dictionary<string, PersonData> ...;
Dictionary<string, PersonData> ...;
I'd recommend encapsulating all of this into a facade class that hides the implementation details.
Could you use an sqlite database as the backing? With sqlite you even have the option of building an in-memory db.