I'm aware that an ArrayList is probably not the way to go with this particular situation, but humor me and help me lose this headache.
I have a constructor class like follows:
class Peoples
{
public string LastName;
public string FirstName;
public Peoples(string lastName, string firstName)
{
LastName = lastName;
FirstName = firstName;
}
}
And I'm trying to build an ArrayList to build a collection by calling on this constructor. However, I can't seem to find a way to build the ArrayList properly when I use this constructor. I have figured it out with an Array, but not an ArrayList.
I have been messing with this to try to build my ArrayList:
ArrayList people = new ArrayList();
people[0] = new Peoples("Bar", "Foo");
people[1] = new Peoples("Quirk", "Baz");
people[2] = new Peopls("Get", "Gad");
My indexing is apparently out of range according to the exception I get.
It should be:
people.Add(new Peoples(etc.));
instead of
people[0] = new people()...;
Or better yet:
List<People> people = new List<People>();
people.Add(new People);
Just to be complete. Using a straight array:
People[] people = new People[3];
people[0] = new People();
Try people.Add(new Peoples("Bar", "Foo");
You should add elements to the list. Like the following
ArrayList people = new ArrayList();
people.Add(new Peoples("Bar", "Foo"));
You need to do
people.Add (new Peoples("Bar", "Foo"));
people.Add (new Peoples("Quirk", "Baz"));
people.Add (new Peoples("Get", "Gad"));
When you attempt to call people[i] without first populating the array list you will get the IndexOutOfRangeException. You must first add to the ArrayList.
ArrayList list = new ArrayList();
list.Add(new Peoples("Bar", "Foo"));
You can then access the list by the index which would be done in a foreach or for loop.
Is there a reason you are not using List<Peoples> which would give you a strongly typed collection?
Also, you have publicly accessible fields in the class although I realise you probably just threw together that code for the question.
You should use the ArrayList.Add function to add to the array list.
ArrayList peoplesArray = new ArrayList();
peoplesArray.Add(new Peoples("John","Smith");
FYI, ArrayList is considered evil by many. As Kevin said, it would be better to us List<People>.
List is what is called a generic. Google 'strongly typed', 'boxing', and 'generics' for a better understanding of why.
back to your original question:
An array's size must be declared when instantiated, i.e.
People[] people = new People[5];
this creates 5 empty cells in the array so you can access the cells using a subscript i.e. [0]
An ArrayList or List<T> when instantiated using the default constructor has no cells i.e.
List<People> people = new List<People>();
people[0] does not exist at this point.
use people.Add(new People("first", "last")); to add a new cell to the list. now the subscript [0] is valid, but [1] is still invalid because there is only one cell.
A list i.e. ArrayList or List can grow dynamically by using .Add(). Once added to a list, you can reference them using the subscript [i], but you cannot use the subcript to add them.
Related
I'm not sure if this is possible or even makes total sense, but I need to add an object let's call it Person to an ICollection List People and add the collection to a List<> , in order to have the collection of people in a List<> that also will contain other parameters.
I am not sure how to do this but I can show you what I have sketched so far.
public void addPeopleToList(string PersonId)
{
Person p = findPerson(PersonId); /*Method that takes the ID and
returns an object from another List*/
ICollection<People> ICollectionPeople; //Create the ICollection
ICollectionPeople.Add(p); //Add Person to Collection
List.Add(ICollectionPeople); //Add Collection to List
}
If this way is not the proper way to do it, I am open to all other suggestions.
It's probably easier if you simply told us what exactly you want to achieve, but anyway:
You need to assign a value to ICollectionPeople (also maybe it's worth renaming it and following the naming conventions). Maybe
ICollection<People> peopleCollection = new List<People>();
Though do you really need that explicit type? You could use var.
You need to create an instance of the list you want to add your collection of people to. Maybe
var list = new List<People>();
Then finally, use AddRange() like
list.AddRange(peopleCollection);
I think what you need is another class.. like...
public class PersonWithAttributes : Person {
// add attribute properties here
}
Then in your code above you would change List to be of type List<PersonWithAttributes> and instead of .Adding the collection you would call List.AddRange(ICollectionPeople). After which you would need to loop over the List items and add the extra attributes you were talking about.
Not sure but looks like you wanted to have a List<List<People>> .. if that's so then your code is missing initialization of the collection. You need to change a bit
public void addPeopleToList(string PersonId)
{
Person p = findPerson(PersonId); /*Method that takes the ID and
returns an object from another List*/
List<Person> ICollectionPeople = new List<Person>(); //Create the
ICollectionPeople.Add(p); //Add Person to Collection
List<List<Person>> personLists = new List<List<Person>>()
personLists.Add(ICollectionPeople); //Add Collection to List
}
EDIT:
To whoever marked the question as duplicate. That question is for how to create a deep copy. My question was how to make sure a the copy constructor is called when copying a list of class elements.
I'm trying to make a deep copy of a List that contain custom class elements. If I have a List of strings I can just use
List<string> secondList = new List<string>(firstList);
and then freely modify the elements in the second list without effeting the ones in the firwst list. But when I try to do the same with a custom class type both lists get changed. To try and solve it I made a small test program that just has this class.
class TestClass
{
public string name;
public TestClass(string n)
{
name = n;
}
public TestClass(TestClass original)
{
name = original.name;
}
}
And all my program does is this
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>(list1);
list2[0].name = "Name2";
That last line of code changes the name of the first element in both lists, which I do no want.
The issue here is that your objects are reference types, and the lists hold references to those objects.
This means that even though your second list has a COPY of the references from the first list, the references are still pointing to the original objects.
In order to solve this, you must clone not the references in the lists but instead the actual objects that you have stored in the lists.
You have already defined a copy constructor for your class, so you can use that to make a deep copy of the list as follows:
var list2 = list1.Select(item => new TestClass(item)).ToList();
You create a reference with this line of Code:
List<TestClass> list2 = new List<TestClass>(list1);
But you won't like to use Call-by-Reference. You Need Call-by-Value
in this Approach.
so the working code in lambda-expression is the following one:
TestClass t = new TestClass("Name1");
List<TestClass> list1 = new List<TestClass>();
list1.Add(t);
List<TestClass> list2 = new List<TestClass>();
list2 = list1.Select(item => new TestClass(item)).ToList();
list2[0].name = "Name2";
Have fun with it...
What would be the best way to make a System.Collections.Generic.List that should only be accessed by an enum? To help describe what I'm looking for, this how I'm doing it right now:
enum MyEnum
{
First,
Second,
Count
}
class MyClass
{
List<SomeClass> myList = new List<SomeClass>((int)MyEnum.Count);
MyClass()
{
myList[(int)MyEnum.First] = new SomeClass(1);
myList[(int)MyEnum.Second] = new SomeClass(2);
}
}
I feel like I'm missing something. Is there a better way of doing this? I'm sorry if the answer is obvious, I found it very difficult to search for something that sounded so generic.
As some background, I would be using this list to access different textures in my code, e.g. the enum would have texture names and each texture would be placed in and later accessed from the List using that texture name.
Would it be possible to use Dictionary instead of List?
var myDict = new Dictionary<MyEnum, SomeClass>();
...
myDict[MyEnum.First] = new SomeClass(1);
myDict[MyEnum.Second] = new SomeClass(2);
Or, as #JimHurley suggested (see http://msdn.microsoft.com/en-us/library/bb531208.aspx) just
var myDict = new Dictionary<MyEnum, SomeClass>()
{
{ MyEnum.First, new SomeClass(1)},
{ MyEnum.Second, new SomeClass(2)}
};
If you want to add a new element to List<T> you have to use it's Add method.Indexer can be used only to modify existing items. I think in this case using a Dictionary<MyEnum, SomeClass> would be more appropriate.
it is possible to store data in of two arraylist into <list>?
here's my code with two arrays that will merge:
ArrayList arrPrices = new ArrayList();
List<StockInfoPrice> lstStockInfoPrice = new List<StockInfoPrice>();
Util oUtils = new Util();
arrPrices = oUtils.GetPrices(SymbolIndex);
ArrayList arrDetails = new ArrayList();
List<StockInfoDetails> lstStockInfoDetails = new List<StockInfoDetails>();
Util oUtils = new Util();
arrPrices = oUtils.GetDetails(SymbolIndex);
You can do it with linq simply:
lstStockInfoPrice.AddRange(arr1.Cast<StockInfoPrice>());
lstStockInfoPrice.AddRange(arr2.Cast<StockInfoPrice>());
See Cast in IEnumerable.
It is possible.
You could try the following if oUtils.GetPrices(SymbolIndex) returns StockInfoPrice;
lstStockInfoPrice.AddRange(oUtils.GetPrices(SymbolIndex));
I this Util class isn't your own, then you're stuck with Marius' answer. However, if you control that Util class then you could make the GetPrices and GetDetails methods return someting with type IEnumerable and IEnumerable respectively.
Then, you can add the whole lot to another list with List.AddRange() method.
As an aside, your allocation in the declaration of arrPrices is a waste of time - the allocated object is never used and will then be subject to garbage collection.
Your GetPrices() method returns an ArrayList - ie, a new arrayList, and
arrPrices = oUtils.GetPrices(SymbolIndex);
simply makes arrPrices refer to the new list. There are then no references to the one you allocated when you declared arrPrices, so it's thrown away.
Do it like this:-
ArrayList arrPrices;
List<StockInfoPrice> lstStockInfoPrice = new List<StockInfoPrice>();
Util oUtils = new Util();
arrPrices = oUtils.GetPrices(SymbolIndex);
If you want to move the value from arrPrices to lstStockInfoPrice and lstStockInfoDetails, you could iterate over the array list and put the elements in the list. Something like this:
foreach(var o in arrPrices)
{
lstStockInfoPrice.Add(o); // or Add((StockInfoPrice)o)
}
At the moment I am using one list to store one part of my data, and it's working perfectly in this format:
Item
----------------
Joe Bloggs
George Forman
Peter Pan
Now, I would like to add another line to this list, for it to work like so:
NAME EMAIL
------------------------------------------------------
Joe Bloggs joe#bloggs.com
George Forman george#formangrills.co
Peter Pan me#neverland.com
I've tried using this code to create a list within a list, and this code is used in another method in a foreach loop:
// Where List is instantiated
List<List<string>> list2d = new List<List<string>>
...
// Where DataGrid instance is given the list
dg.DataSource = list2d;
dg.DataBind();
...
// In another method, where all people add their names and emails, then are added
// to the two-dimensional list
foreach (People p in ppl.results) {
list.Add(results.name);
list.Add(results.email);
list2d.Add(list);
}
When I run this, I get this result:
Capacity Count
----------------
16 16
16 16
16 16
... ...
Where am I going wrong here. How can I get the output I desire with the code I am using right now?
Why don't you use a List<People> instead of a List<List<string>> ?
Highly recommend something more like this:
public class Person {
public string Name {get; set;}
public string Email {get; set;}
}
var people = new List<Person>();
Easier to read, easy to code.
If for some reason you don't want to define a Person class and use List<Person> as advised, you can use a tuple, such as (C# 7):
var people = new List<(string Name, string Email)>
{
("Joe Bloggs", "joe#bloggs.com"),
("George Forman", "george#formangrills.co"),
("Peter Pan", "me#neverland.com")
};
var georgeEmail = people[1].Email;
The Name and Email member names are optional, you can omit them and access them using Item1 and Item2 respectively.
There are defined tuples for up to 8 members.
For earlier versions of C#, you can still use a List<Tuple<string, string>> (or preferably ValueTuple using this NuGet package), but you won't benefit from customized member names.
Where does the variable results come from?
This block:
foreach (People p in ppl.results) {
list.Add(results.name);
list.Add(results.email);
list2d.Add(list);
}
Should probably read more like:
foreach (People p in ppl.results) {
var list = new List<string>();
list.Add(p.name);
list.Add(p.email);
list2d.Add(list);
}
It's old but thought I'd add my two cents...
Not sure if it will work but try using a KeyValuePair:
List<KeyValuePair<?, ?>> LinkList = new List<KeyValuePair<?, ?>>();
LinkList.Add(new KeyValuePair<?, ?>(Object, Object));
You'll end up with something like this:
LinkList[0] = <Object, Object>
LinkList[1] = <Object, Object>
LinkList[2] = <Object, Object>
and so on...
You should use List<Person> or a HashSet<Person>.
Please show more of your code.
If that last piece of code declares and initializes the list variable outside the loop you're basically reusing the same list object, thus adding everything into one list.
Also show where .Capacity and .Count comes into play, how did you get those values?