I'm looking for a way to initialize a variable of type List with a set of values (in C#). Yes, there is object initialization but that requires a new object for each value you want and I would rather avoid it.
Here's a sample:
class MyObject
{
public string Name {get;set;}
}
List<MyObject> OldNames = new List<MyObject>(10);
List<MyObject> NewNames = new List<MyObject>(5);
This is fine and dandy but OldNames contains 10 null references to an object of type MyObject.
Using a list initializer I could do this:
List<MyObject> OldNames = new List<MyObject>{
new MyObject(),
new MyObject(),
new MyObject(),
etc.
That's kind of a pain as I have many list variables and various sizes to initialize (for exaample one variable is a list of 26 objects. Yes, I could write a function or maybe extension to do this initialization for me (in a loop where I provide the size) but again that's code I don't necessarily want to write.
I'm hoping there's some kind of lamdba or LINQ expression or something to initialize a list of objects to values instead of nulls.
Thanks!
Use the Enumerable.Range LINQ method to specify the number of iterations.
List<MyObject> NewNames = Enumerable.Range(1,5).Select(i => new MyObject()).ToList();
The number 1 here is arbitrary, as the indexer is not used in any way.
Just a quick musing... you can use Enumerable.Repeat... just not the way it's been done before. This would work:
var query = Enumerable.Repeat<Func<MyObject>>(() => new MyObject(), count)
.Select(x => x())
.ToList();
I'm not suggesting you should do this, but it's an interesting alternative to Enumerable.Range.
Create yourself a create and initialize function.
public List<T> CreateAndInitialize<T>(int size, Func<int, T> init)
{
var result = new List<T>(size);
for (int i = 0; i < size; ++i)
result.Add(init(i));
return result;
}
Then
List<MyObject> newNames = CreateAndInitialize(15, i => return new MyObject());
I chose to pass in the index of the object in the init delegate so that you could account for that if needed.
Looks to me you are just missing the () parenthesis after the new declaration.
private List<MyObject> ObjectList = new List<MyObject>()
{
new MyObject() { property1= Value1, property2 = "Value2"},
new MyObject() { property1= Value1, property2 = "Value2"}
};
Related
Apologies in advance if the question header is confusing. I'll try to explain with an example, hopefully it would be clear.
I've a class like below :
class A
{
Dictionary<string,string> myDict;
}
I want to create a list of classes with the above(ex: List) using some input which would be another List of the following type:
class input
{
public string elem1;
public string elem2;
public string elem2;
public string elem2;
}
Ex: List<input> inputList;
I've accomplished the same using a foreach loop like below. I want to know, if I can accomplish the same using LINQ in a better way:
var result = new List<A>();
foreach (var l in inputList)
{
var r = new A();
r.myDict.Add("elem1",l.elem1);
r.myDict.Add("elem1",l.elem1);
r.myDict.Add("elem1",l.elem1);
r.myDict.Add("elem1",l.elem1);
result.Add(r);
}
Easy to do with linq,
input ip = new input();
Dictionary<string, string> myDictionary = typeof(input).GetFields(BindingFlags.Instance | BindingFlags.Public).ToDictionary(x => x.Name, x => x.GetValue(ip).ToString());
If you want to have generic code for any class then the best way to solve this problem is to use ToDictionary method and reflection. To retrieve all public fields with its values use code below:
var result = inputList
.Select(item => new A() {
myDict = item
.GetType() // get item's type declaration
.GetFields(BindingFlags.Instance | BindingFlags.Public)) // get all public non static fileds of item's class
.ToDictionary(f => f.Name, f => f.GetValue(item) // get dictionary with field name as the key and field value as the value
})
.ToList();
If you need to retrieve not only public members or properties instead of fields you can use other methods of class Type. You can also create more generic algorithm and retrieve only needed fields using special attribures to its fields and GetCustomAttributes method.
Note that the myDict field must be public.
Linq version can be something like this (if you want a concise code):
List<A> result = inputList // For each item in inputList
.Select(item => new A() { // Create A instance
myDict = new Dictionary<string, string>() { // Assign myDict within A by a dictionary
{"elem1", item.elem1}, // Which has 4 items
{"elem2", item.elem2},
{"elem3", item.elem3},
{"elem4", item.elem4},
}
})
.ToList(); // Materialize as a List<A>
Is it more (or less) readable than the original code is an open question.
You could try this:
inputList
.Select(i => new A(){myDict = new Dictionary<string, string>{{"elem1", i.elem1},{"elem2", i.elem2},{"elem3", i.elem3},{"elem4", i.elem4}}})
.ToList();
This requires that myDict is public field, but from your question I think it is (or the code must be inside the class).
Also, I think you have wrong field names, because they aren't unique and such code wouldn't compile, but I assumed that names should be elem1, elem2, elem3, elem4.
I have two list
static List<dynamic> List1= new List<dynamic>();
list<string> List2
List1 is {Message='asdasd',Mobilenum=995955}
i want to remove all elements from List1 if the value in list2 is there in list1?
I have done this but it is not working
List1.RemoveAll(c => list2.ToList().Exists(n => n.Mobilenum== c.Values));
List1.RemoveAll(c => List2.Contains(c.Mobilenum));
But replace dynamic with the real type. Normally you don't need to use it. If it's an anonymous type and you have to pass this list around, consider to implement a new type with these properties.
First, create a type instead of using dynamic:
public class MyType
{
public string Message;
public string Mobilenum;
}
Then, you can do:
var List1 = new List<MyType>();
// ...build your list
var List2 = new List<string>();
// ...build your other list
var res = List1.Where(x => !List2.Contains(x.Mobilenum));
Avoid using Remove unless you're sure you want to throw away the information instead of just "filtering" it for a particular use.
I have a question about Enumerable.Repeat function.
If I will have a class:
class A
{
//code
}
And I will create an array, of that type objects:
A [] arr = new A[50];
And next, I will want to initialize those objects, calling Enumerable.Repeat:
arr = Enumerable.Repeat(new A(), 50);
Will those objects have the same address in memory?
If I will want to check their hash code, for example in that way:
bool theSameHashCode = questions[0].GetHashCode() == questions[1].GetHashCode();
This will return me true, and if I will change one object properties, all other objects will change it too.
So my question is: is that properly way, to initialize reference type objects? If not, then what is a better way?
Using Enumerable.Repeat this way will initialize only one object and return that object every time when you iterate over the result.
Will those objects have the same address in memory?
There is only one object.
To achieve what you want, you can do this:
Enumerable.Range(1, 50).Select(i => new A()).ToArray();
This will return an array of 50 distinct objects of type A.
By the way, the fact that GetHashCode() returns the same value does not imply that the objects are referentially equal (or simply equal, for that matter). Two non-equal objects can have the same hash code.
Just to help clarify for Camilo, here's some test code that shows the issue at hand:
void Main()
{
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
foos[0].Name = "Jack";
foos[1].Name = "Jill";
Console.WriteLine(foos[0].Name);
}
public class Foo
{
public string Name;
}
This prints "Jill". Thus it shows that Enumerable.Repeat is only creating one instance of the Foo class.
When using the following code to create an array:
var foos = Enumerable.Repeat(new Foo(), 2).ToArray();
The reason why each location in the array is the same is because you are passing an object, and not a function that creates an object, the code above is the same as:
var foo = new Foo();
var foos = Enumerable.Repeat(foo , 2).ToArray();
The reason above also explains why using a Select statement, like in the code below, creates a new object for each entry, because you are passing a function that dictates how each object is created, rather than the object itself.
Enumerable.Range(1, 2).Select(i => new Foo()).ToArray();
I would use a simple for loop to populate an array with new reference types.
I want to query a set I already have and create new objects from the results. I also want those objects to be added to an existing LinkedList.
What I have right now is
var results = fulldata.Where(x => x.ImportantData == ImportanceLevel.HIGH);
Now results contain a set of data objects defined liked this :
public class DataObject{
public int x;
public int y;
public int DataType;
}
I'd like to write with the same syntax (as the Where() list comprehension method) an equivalent of the following code :
var prunedResults = new LinkedList<KeyValuePair<int, int>>();
foreach(var res in results){
if(res.DataType == DataTypeSpecial){
prunedResults.Add(new KeyValuePair<int, int>(res.x, res.y));
}
}
I'm pretty new to "modern" C# so if you could also define terms used here, it would help me to google further answers. What I mean is that this seems to be called LINQ and the Where() call is using a lambda expression, but I could be somewhat wrong.
var prunedResults = new LinkedList<KeyValuePair<int, int>>();
//do other stuff to prunedResults
prunedResults.AddRange(results.Where(x => x.DataType == DataTypeSpecial)
.Select(res=> new KeyValuePair<int, int>(res.x, res.y)));
How can I sort a list of list?
persons.OrderBy(p => p.rate).ToList();
The list of list (persons) is declared like this:
public class Persons : List<Person> { }
When I'm trying to run the first statement I get an error:
Cannot convert from 'System.Collections.Generic.List' to
'Persons'
Is there a way to do this using LINQ?
Just because it inherits from a list doesn't mean you can use it like one.
Remember for everything else to see it as a list use interfaces (IList<T>). Then methods depending on IEnumerable, IList, ICollection, etc. can see that it's something it can deal with.
Otherwise, whose to say your Add() (As defined by IList) method isn't named AddPerson in your class?
You can achive it with that statement:
var persons = new Persons ();
persons.AddRange(persons.OrderBy(p => p.rate));
If you want to order all persons in all lists and huddle up them into one list:
var persons = new System.Collections.Generic.List<Persons>();
var trio = new Persons() { new Person(7), new Person(3), new Person(8) };
var pair = new Persons() { new Person(1), new Person(2) };
persons.Add(trio);
persons.Add(pair);
var ordered = persons.SelectMany(p => p).OrderBy(p => p.rate).ToList();
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany.aspx
To achieve a SortBy behavior, you have to follow these three easy steps:
Store the old items (a. by storing the reference to the old list | b. by copying all entries of the old list into a new one)
Create an empty instance of your container class (a. by creating a new object of the needed type | b. by clearing the old list)
Fill your empty list with the entries while ordering them as you desire.
This little extension method should do the Trick:
public static void SortBy<TList, TItem, TOrder>(this TList source,
Func<TItem, TOrder> sortFunc)
where TList : List<TItem>
{
var l = source.ToList();
source.Clear();
source.AddRange(l.OrderBy(sortFunc));
}