I have a List<int> myInts and want to multiply all with 10. I want to use linq (not foreach loop).I tryed this but nothing happend:
List<int> myInts = new List<int>() { 1, 2, 3 };
myInts .ForEach(act => act=act*10);
Of what do I have to take care in the .ForEach(...) part? And yes, I want to use ForEach if it is somehow possible.
Probably its simple, but I cant see it, I apoligize. Thank you all!
This creates a new instance of List.
myInts = myInts.Select(p=>p*10).ToList();
Another and simpler solution:
list = list.ConvertAll(i => i * 10);
"Nothing happens" because reassigning to the local variable (act) has no effect in the caller (ForEach) - C# is Call By Value (except for ref/out parameters).
To modify the list in place, simply use a standard for-each over the indices (which I find readable and upfront of the side-effect intent):
var myInts = new List<int>() { 1, 2, 3 };
for (var i = 0; i < myInts.Count; i++) {
myInts[i] = myInts[i] * 10;
}
To perform the operation and create a new list/sequence (which can be re-assigned to the same variable), see IEnumerable.Select which is a map transformation.
From MSDN documentation:
Modifying the underlying collection in the body of the Action<T> delegate
is not supported and causes undefined behavior.
So, you need to project your exisistin List into a new one, or you need to use a for loop if you must modify the List "in place"
Regards
What is happening is that you are getting a value copy of the int to your the lambda, which so you won't be able to change the 'external' int.
How about projecting a new list?
List<int> myInts = new List<int>() { 1, 2, 3 };
myInts = myInts.Select(act => act*10).ToList();
To use a .Select or .ConvertAll are good solutions.
But my intention was to let "ForEach" return an alterd list.
I found out, over msdn documentation, that this isnĀ“t possible because ForEach is a void type and has no returntype.
This kind of action works if I would have objects in my List instead of ints. Then I would be able to use the "void" Method to change the properties of my objects.
Do you mean like this ?
List<int> _tempList = new List<int>();
myInts.ToList().ForEach(x => _tempList.Add(x * 10));
try this:
Enumerable.Range(0, myInts.Count).ToList().ForEach(i => myInts[i] = myInts[i] * 10);
Related
I've stumbled upon a List<T> behaviour that I'm not quite sure I can understand.
I have the following example code
List<int> myInts = new List<int>() {1, 2, 3, 4, 5};
myInts.ForEach( x => x += 1);
The list however, remains unchanged after the ForEach statement. Can someone explain to me why?
int is a value type, which means when the lambda function in the ForEach is called, a copy of the int value is passed, rather than the lambda having a reference available to the original value. It is this copy that is being modified, not the original value in the list.
If you wish to modify the list, you either need to loop through the list modifying each entry individually, or return and assign a new list with the updated values:
//loop through and modify:
for (var x = 0; x < myInts.Count; x++)
myInts[x] += 1;
//or use Select to construct a new list:
myInts = myInts.Select(x => x += 1).ToList();
James Thorpe's answer is totally correct, but I'd like to elaborate on what the difference between ForEach and Select on IEnumerable is.
ForEach
This should be used when you want to use a block lambda (meaning more than just a single expression like most lambda expressions). Generally speaking, this is not heavily used (for the reason you've experienced); you're better off just using a foreach block.
Select
This is for projecting the contents of an IEnumerable into another form; meaning it's exactly what you're looking for. It should be used when you want to go through each element and transform the contents into something else.
This is how I remove an item from a List. Is this the right way? Is there any cleaner/faster way to achieve this.
List<ItemClass> itemsToErase = new List<ItemClass>();
foreach(ItemClass itm in DS)
{
if(itm.ToBeRemoved)
itemsToErase .Add(itm);
}
foreach(ItemClass eraseItem in itemsToErase)
{
DS.Remove(eraseItem );
}
EDIT: DS is of type List<ItemClass>
EDIT: Have one more doubt. What if DS is a LinkedList<ItemClass>. There is no RemoveAll() for that.
There is List.RemoveAll() which takes a delegate where you can add your comparison function.
E.g.:
List<ItemClass> itemsToErase = new List<ItemClass>();
itemsToErase.RemoveAll( itm => itm.ToBeRemoved );
You can use the RemoveAll() method:
DS.RemoveAll(x => x.ToBeRemoved);
This is a O(n) operation, your code is O(n^2).
This methods avoids a lot of copies in the orginal List but has a greater memory consumption.
List<ItemClass> newList = new List<ItemClass>(originalList.Count);
foreach(var item in originalList) {
if (!item.ToBeRemoved)
newList.Add(item);
}
originalList = newList;
Not really, the logic remains the same no matter how you do it. You cannot iterate over and modify a collection at the same time. It looks cleaner with LINQ:
var list = new List<int> { 1, 2, 3, 4, 5 };
var except = new List<int> { 3, 4 };
var result = list.Except(except);
Hope this helps.
edit: Even list.RemoveAll(...) has to maintain two lists internally to do it.
edit2: Actually svick is right; after looking at the implementation, RemoveAll is fastest.
use this method
DS.RemoveAll(x => x.ToBeRemoved);
Your code is a common solution to the problem and is fine. Especially if there are only a few items to be removed.
As others have suggested you can also create a new list containing the items you want to keep and then discard the old list. This works better if most items are going to be removed and only a small number kept.
When picking either of these methods keep in mind that both require the allocation of a new list object. This extra memory allocation probably isn't an issue but might be, depending on what the rest of the code is doing.
As others have mentioned there is also the RemoveAll method. This is what I would use, it is neat, clear and as efficient as anything using a list can be.
The last option is to use an index to loop through the collection. EG.
(Sorry for the VB, I use it more often than C# and didn't want to confuse by getting the syntax wrong)
Dim i as Integer
Do While i<DS.Count
If DS.Item(i).ToBeRemoved Then
DS.RemoveAt(i)
Else
i+=1
End If
Loop
What is the best way to convert a List to SortedList? Any good way to do it without cycling through it? Any clever way to do it with an OrderBy()?
WRAP UP
Please read all answers and comments.
Do you mean:
you have a List<T> and wish it to be sorted in place?
you have a List<T> and wish to create another 'list' which is itself sorted
you have a List<T> and wish to make a SortedList<T,T> where the key is the same as the value
Assuming input:
var x = new List<int>() { 3, 2, 1 };
1 is trivial
x.Sort();
2 is trivial
// sx is an IOrderedEnumerable<T>, you can call ToList() on it if you want
var sx = x.OrderBy(i => i);
3 is trivial with a copy
var s = new SortedList<int,int>(t.ToDictionary(i => i));
and more efficiently:
var s = new SortedList<int,int>();
foreach (var i in x) { s[i] = [i]; }
I can't see why you would want to do 3 but there you go.
var list = new List<string>();
var sortedList = new SortedList<string, string>(list.ToDictionary(s => s));
Now I have no clue how efficient this is, but it's one line of code :) Also, in this example I just used the string itself as the selector. In a real scenario, you should know ahead of time what you'd like to use as a selector.
Understand that a List<T> is a smart array, and a SortedList<T, U> is a key/value binary tree. Since there's no relationship between their structures, there can't possibly be a more effective way to do it rather than simply taking each element from the list and putting it into the tree.
If you mean "sorted list" instead of "SortedList," then it's trivial to sort your list via either List.Sort() or an appropriate OrderBy().
List unsortedPersons = new List();
// ... Populate unsortedPersons ...
var sorted = from person in unsortedPersons
orderby person.Name
select person;
The LINQ gives you an ISortedEnumerable i believe, which may be good enough for your purposes.
I'd like to populate an arraylist by specifying a list of values just like I would an integer array, but am unsure of how to do so without repeated calls to the "add" method.
For example, I want to assign { 1, 2, 3, "string1", "string2" } to an arraylist. I know for other arrays you can make the assignment like:
int[] IntArray = {1,2,3};
Is there a similar way to do this for an arraylist? I tried the addrange method but the curly brace method doesn't implement the ICollection interface.
Depending on the version of C# you are using, you have different options.
C# 3.0 has collection initializers, detail at Scott Gu's Blog
Here is an example of your problem.
ArrayList list = new ArrayList {1,2,3};
And if you are initializing a collection object, most have constructors that take similar components to AddRange, although again as you mentioned this may not be an option.
Array list has ctor which accepts ICollection, which is implemented by the Array class.
object[] myArray = new object[] {1,2,3,"string1","string2"};
ArrayList myArrayList = new ArrayList(myArray);
(kind of answering my own question but...)
The closest thing I've found to what I want is to make use of the ArrayList.Adapter method:
object[] values = { 1, 2, 3, "string1", "string2" };
ArrayList AL = new ArrayList();
AL = ArrayList.Adapter(values);
//or during intialization
ArrayList AL2 = ArrayList.Adapter(values);
This is sufficient for what I need, but I was hoping it could be done in one line without creating the temporary array as someone else had suggested.
Your comments imply you chose ArrayList because it was the first component you found.
Assuming you are simply looking for a list of integers, this is probably the best way of doing that.
List<int> list = new List<int>{1,2,3};
And if you are using C# 2.0 (Which has generics, but not collection initializers).
List<int> list = new List<int>(new int[] {1, 2, 3});
Although the int[] format may not be correct in older versions, you may have to specify the number of items in the array.
I assume you're not using C# 3.0, which has collection initializers. If you're not bothered about the overhead of creating a temp array, you could do it like this in 1.1/2.0:
ArrayList list = new ArrayList(new object[] { 1, 2, 3, "string1", "string2"});
Can you cast a List<int> to List<string> somehow?
I know I could loop through and .ToString() the thing, but a cast would be awesome.
I'm in C# 2.0 (so no LINQ).
.NET 2.0 has the ConvertAll method where you can pass in a converter function:
List<int> l1 = new List<int>(new int[] { 1, 2, 3 } );
List<string> l2 = l1.ConvertAll<string>(delegate(int i) { return i.ToString(); });
Updated for 2010
List<int> l1 = new List<int>(new int[] { 1,2,3 } );
List<string> l2 = l1.ConvertAll<string>(x => x.ToString());
Is C# 2.0 able to do List<T>.Convert? If so, I think your best guess would be to use that with a delegate:
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Convert(delegate (int i) { return i.ToString(); });
Something along those lines.
Glenn's answer is probably the correct code ;-)
You can use:
List<int> items = new List<int>(new int[] { 1,2,3 } );
List<string> s = (from i in items select i.ToString()).ToList();
You wouldn't be able to directly cast it as no explicit or implicit cast exists from int to string, it would have to be a method involving .ToString() such as:-
foreach (int i in intList) stringList.Add(i.ToString());
Edit - or as others have pointed out rather brilliantly, use intList.ConvertAll(delegate(int i) { return i.ToString(); });, however clearly you still have to use .ToString() and it's a conversion rather than a cast.
result = listOfInt.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToList()
replace the parameters result and listOfInt to your parameters
Converting from int List to string List can be done in two adittional ways besides the usual ToString(). Choose the one that pleases you more.
var stringlist = intlist.Select(x=>""+x).ToList();
Or also:
var stringlist = intlist.Select(x=>$"{x}").ToList();
And finally the traditional:
var stringlist = intlist.Select(x=>x.ToString()).ToList();
You have to build a new list. The underlying bit representations of List<int> and List<string> are completely incompatible -- on a 64-bit platform, for instance, the individual members aren't even the same size.
It is theoretically possible to treat a List<string> as a List<object> -- this gets you into the exciting worlds of covariance and contravariance, and is not currently supported by C# or VB.NET.