This question already has answers here:
How to empty a list in C#?
(7 answers)
Closed 8 years ago.
This has probably been asked somewhere, but I was unable to find it.
I have a List of strings like this :
public static List<string> AnimalsL = new List<string>();
public static void ListAnimals()
{
AnimalsL.Add("Animal one");
AnimalsL.Add("Animal two");
}
public static void ReturnAnimals()
{
string[] Animals = AnimalsL.ToArray();
if(AnimalsL != null)
{
for(int Index = 0; Index < Animals.Length; Index++)
{
System.Windows.Forms.MessageBox.Show(Animals[Index].ToString());
}
}
}
[b] Above is working code [/b]
So, as the title says, my real question is : How to completely empty a List of strings ?
For instance, I could want to store the animal names IF the animals type is snake, or dog, and I wouldn't want them crossing into the same category, or if I want to ensure the list is empty before adding to it, or clear it once I've used my methods on the animal.
I was thinking of declaring Animals[] = string.Empty, but this wouldn't actually clear the list ..
There are two ways to do this.
1.
AnimalsL.Clear(); // clears all the items in the list
2.
AnimalsL = new List<string>(); // assigns a new instance
Actually, creating a new instance is faster than calling the Clear method, though if you want to keep the reference to that object, then calling Clear is better.
Here is a benchmark for Clear() vs new List Link
Use List<T>.Clear() method to remove all entries from a list instance.
Related
This question already has answers here:
How do I clone a generic list in C#?
(29 answers)
C# Value and Reference types
(6 answers)
Closed 4 years ago.
class ListHolder
{
public List<char> List;
public ListHolder(List<char> l)
{
this.List = l;
}
}
class Program
{
static void Main(string[] args)
{
List<char> a = new List<char>();
a.Add('s');
ListHolder c = new ListHolder(a);
a.Clear();
Console.WriteLine(c.List.Count);
}
}
I've put some list into that class, than I cleared the list and wrote the count of the list in the class... I would expect that the output should be "1" (as the list in the class contains the letter 's') but instead it writes "0". How is possible, that a.Clear clears even the list in the class? How can I achieve clearing only the list in the Main and the list in the class letting be?
Since you are passing a reference instead of the list itself, you will get 0 after clearing your list.
What you have to do is passing to the class a new List containing the other list's values:
cl c = new cl(new List<char>(a));
This way, even if you clear the 'main' list, in your class you'll have 1 as items count.
Hope this helps.
List and other classes are reference types. In few words, it means you have an object somewhere in memory and a reference(s) on it.
this.l = l; means you copied the reference to the first list to the class field. So you have one list and two references on it. And when you clear the list via a variable, no matter how you address it after clearing - via a or cl.l. Your single list is cleared already.
If you want to avoid this, you need to create a copy of list in your constructor:
public cl(List<char> l)
{
this.l = new List<char>();
this.l.AddRange(l);
}
}
I recommend you to read more information about reference types. They are used widely and knowledge about them will give you a good base for programming skills.
if (a is System.ValueType)
{
//never
Console.WriteLine("List is value type");
}
if ('s' is System.ValueType)
{
//always
Console.WriteLine("char is value type");
}
I think you know, char is value type, but list is reference type.
Even code like this; it would be same.
List<char> a = new List<char>();
a.Add('s');
List<char> c = a;
a.Clear();
Console.WriteLine(c.Count);
This question already has an answer here:
Reason for KeyNotFoundException in Dictionary initialization
(1 answer)
Closed 4 years ago.
A KeyNotFoundException ("The given key was not present in the dictionary") is being thrown upon initialization of a static dictionary. The code is as follows:
public class Test {
static public Dictionary<string,List<string>> dictionary = new Dictionary<string,List<string>>() {
["key1"] = {"testing","testingagain"},
["key2"] = {"testing","testingagain"}
};
}
However, if the dictionary is initialized using List constructors explicitly, it is successful:
public class Test {
static public Dictionary<string,List<string>> works = new Dictionary<string,List<string>>() {
["key1"] = new List<string>() {"testing","testingagain"},
["key2"] = new List<string>() {"testing","testingagain"}
};
}
I would think that since the first one compiles fine the compiler would know that they are List<string> objects, and the examples would give the same results. Why are they not?
Because List<T> implements IEnumerable and contains a definition for Add, alongside with how the collection-initializers work in C#, the declaration is valid at compile-time, but again since you've not actually initialized the List<string> it becomes invalid at run-time due to memory allocation.
Because a list has to get „created“ so whenever you do something with a list you have to use new List<t>()
Else the list is null so you cant put stuff in it.
This question already has answers here:
How to modify a foreach iteration variable from within foreach loop?
(4 answers)
Is there any way to do this, assign a value within a List<T>.ForEach() statement?
(4 answers)
Closed 7 years ago.
It seems weird to me. Thought if someone can clear my doubt please.
var list = new List<SomeClass>();
Now if we use ForEach extension method of collection
list.ForEach(c=>c.SomeProperty = SomeValue);
So now we can get the updated value. So it seems to be reference type. And Yes ForEach takes an Action so its reference type. But if try to re-initilize the object inside the ForEach I do not see expected behavior.
list.ForEach(c=>{
if(SomeCondition) // lets consider its always true now.
{
c = new SomeClass();
}
});
So after this execution I was expecting fresh list. And should not contain the reference of old object. But if I print the list. I can see the old values.
So why ForEach didnt re-initialize the objects in list? While we saw ForEach was reference type on value type
Regardless of whether the type of c is a reference type or a value type, when setting a variable c = something, you are overwriting whatever the variable referred to. So the original object that c referred to is no longer referenced. This does not change the list from updating its reference either though, that’s simply not how it works.
If you want to replace some elements in your list by something else, you will need to use Select:
list.Select(c =>
{
if (SomeCondition)
return new SomeClass();
// default case, return the same element
return c;
}.ToList();
Note that this creates a new list, so the old list still contains the same elements.
If you wanted to actually replace elements in the original list, you will have to overwrite the elements in the list by accessing its index. You can do this with a normal for loop:
for (int i = 0; i < list.Count; i++)
{
if (SomeCondition)
{
list[i] = new SomeClass();
}
}
This will actually mutate the existing list and replace some elements inside of it.
I try to write a program where Dictionary is indexed by List. (trust me i do, and yes there are option, but i like indexing by list). There is a minimal working (actually not working, only one last line which is a problem) example:
using System;
using System.Collections.Generic;
namespace test
{
class Program
{
static void Main(string[] args)
{
Dictionary<List<String>, int> h = new Dictionary<List<string>,int>();
List<String> w = new List<string> {"a"};
h.Add(w, 1);
w = new List<string>{"b"};
h.Add(w,2);
w = new List<string>{"a"};
int value = 0;
h.TryGetValue(w, out value);
Console.WriteLine(value+" "+h[w]);
}
}
if one debugs this program, he will clearly see that there two elements in h, but still these elements are not accessible via correct indexes --- h[w]. Am I wrong or is there something weird going on?
The problem with your app extends from the fact that:
new List<String> { "a" } != new List<String> { "a" }
Equality for lists checks to see if the two references refer to the same instance. In this case, they don't. You've instead created two Lists with the same elements...which doesn't make them equal.
You can fix the problem by creating a custom Equality Comparer:
public class ListEqualityComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> list1, List<T> list2)
{
return list1.SequenceEquals(list2);
}
public int GetHashCode(List<T> list)
{
if(list != null && list.Length > 0)
{
var hashcode = list[0].GetHashCode();
for(var i = 1; i <= list.Length; i++)
hashcode ^= list[i].GetHashCode();
return hashcode;
}
return 0;
}
}
And then passing that to the Dictionary constructor:
Dictionary<List<String>, int> h =
new Dictionary<List<string>,int>(new ListEqualityComparer<String>());
The problem is the index by List, what you are indexing by isn't the data in the list but you are essentially indexing by the memory pointer to the List (i.e the memory address of where this List is located).
You Created one list at one memory location, you then created a totally different list at a different memory location (ie when you create a new instance). The two lists are different even though they contain the same data, and this means you can add as many as you want to the dictionary.
One solution is Rather than indexing by List would be to index by String and use a comma separated List containing all the data in your list as an index.
This won't ever work for you, because List<T>'s Equals and GetHashCode methods don't consider the contents of the list. If you want to use a collection of objects as a key, you'll need to implement your own collection type that overrides Equals in such a way as to check the equality of the objects in the collection (perhaps using Enumerable.SequenceEqual.)
The Dictionary class uses reference comparison to look for the specified key, that's why even if the lists contain the same items, they are different.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
List<int> in c#
I have the following program. I am confused about the output.
The line -
Console.WriteLine(listIsARefType.Count) prints 0 instead of 1. Any idea why ?.
class Program
{
static void Main(string[] args)
{
ListTest d = new ListTest();
d.Test();
}
}
class ListTest
{
public void ModifyIt(List<int> l)
{
l = returnList();
}
public void Test()
{
List<int> listIsARefType = new List<int>();
ModifyIt(listIsARefType);
Console.WriteLine(listIsARefType.Count); // should have been 1 but is 0
Console.ReadKey(true);
}
public List<int> returnList()
{
List<int> t = new List<int>();
t.Add(1);
return t;
}
}
Everything in .Net is passed by value by default, even reference types. The difference with reference types is that it's the reference itself that's passed by value. So when you call the ModifyIt() function, you pass a copy of the reference to the function. That function then changes the copied reference. The original list reference is still intact and the list is unchanged. Your code should go like this:
void ModifyIt(List<int> t)
{
t.Add(1);
}
You'll see that now the list does change. You could also do it like this:
void ModifyIt(ref List<int> t)
{
t = returnList();
}
However, you should favor the former style vs the latter. If you already have something like a returnList() function and you really need a function to add those items to an existing list, do it like this:
void ModifyIt(List<int> t)
{
t.AddRange(returnList());
}
Your ModifyIt method name is misleading: it does not modify the list, it replaces it with a new list.
So while List<int> is a reference type you are passing the reference by value. When you change it to point to a new List inside the method that does not affect the reference in the calling method.
You're creating a new instance of List<int> and assigning it. You cannot do that, because when the function returns, the parameter you passed will still be a reference to the old list.
What you need to do is use the ref parameter like so:
public void ModifyIt(ref List<int> l)
{
l = returnList();
}
And then call it like so:
ModifyIt(ref listIsARefType);
You will find that that will function as expected.
The following line:
List<int> listIsARefType = new List<int>();
creates a new list. The number of items in the list is 0. The next line "modifies" the list (but not really, as that is the problem!)
ModifyIt(listIsARefType);
So while you think you've added something, you actually have not. Let's look at what happens when the ModifyIt( ) gets called:
l = returnList();
simply assigns a List<int> of Count 1 to l. But - here's the important part:
The reference l is only the parameter. You have not changed what listIsARefType references. And so, listIsARefType still contains 0 items. l contains 1 item but it is lost as soon as ModifyIt( ) is complete.
Other people can better explain what's happening here, and it's important to know. Jon Skeet has this excellent article on Parameter passing in C#.